기본 사용
const info = useQuery('unique_key', fetchData);
// fetchData는 promise 반환
unique한 key로 정의하며, key에 묶이는 데이터는 비동기 데이터이다.
useQuery가 반환하는 result는 비동기 데이터의 상태를 담고 있다.
- 상태
- loading
- isLoading이 true가 된다.
- error
- isError가 true가 되며, error에 에러 정보가 담긴다.
- success
- isSuccess가 true가 되며, data에 정보가 담긴다.
- idle
- loading
사용 예제
const { isLoading, isError, data, error } = useQuery('key', fetchData);
// const { status, data, error } = useQuery('key', fetchData);
if(isLoading){ // if(status === 'loading')
return <span>Loading..</span>
}
if(isError){
return <span>Error : {error.message}</span>
}
return (
<div>{data}</div>
);
Query Keys
할당해준 key는 cache, refatch, share에 사용된다.
key는 기본적으로 string 형태이지만 array나 object 형태로 가능하다.
string으로 key가 넘겨지면 내부적으로는 해당 string을 포함하는 array로 key가 변환된다.
array나 object는 내부적으로도 그 자체로 key가 된다.
key에 해당하는 array의 내부에 object가 있다면, 해당 object의 내부 요소는 상관없이 같은 object로 취급된다.
- 오른쪽의 셋 다 같은 key
useQuery(['todos', { status, page }], ...)
useQuery(['todos', { page, status }], ...)
useQuery(['todos', { page, status, other: undefined }], ...)
해당 변수가 바뀌면 fetch가 진행되어야 할 때, 해당 변수를 key로 등록하는 것이 좋다.
Query Functions
useQuery에 등록되는 함수는 data를 resolve하고 error를 throw하는 promise를 return 해야 한다.
throw된 error는 error 변수에 저장된다.
axios와 graphql-request는 자동으로 error를 throw하지만, fetch는 그렇지 않으므로 직접 throw하는 함수를 작성해주어야 한다.
query function의 parameter로 설정된 key가 넘겨진다.
Parallel Queries
여러 useQuery를 여러 번 실행하면 query들이 별도의 설정 없이 병렬 실행된다.
render시에 실행되는 query의 개수를 조절해야하는 경우라면, hook의 규칙을 깰 수도 있기 때문에 그냥 쓸 수 없다. 대신에 useQueries hook을 이용해서 동적으로 병렬 실행되는 query의 개수를 제어할 수 있다.
function App({ users }) {
const userQueries = useQueries(
users.map(user => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
})
)
}
useQueries는 query option object의 array를 받아서 result의 array를 반환한다.
Dependent Queries
이전 query가 끝난 후에 실행되는 query이다. useQuery의 enabled 옵션에 있어야 하는 data를 넘겨주면 된다.
useQuery(
['projects', userId],
getProjectsByUser,
{
// The query will not execute until the userId exists
enabled: !!userId,
}
)
- userId가 있어야 실행된다.
enabled 옵션에 false를 넘겨주면 자동으로 query가 실행되지 않는다.
- cached data가 있을 떄는 success를 return 하며 cache된 데이터를 return 한다.
- cached data가 없을 때는 idle 상태가 된다.
- 이제 mount와 동시에 fetch 되지 않는다.
Background Fetching Indicators
query가 refetching되는 것에 대한 상태를 파악하고 싶을 때는 isFetching을 사용하면 된다.
const { status, data: todos, error, isFetching } = useQuery(
'todos',
fetchTodos
)
모든 query가 하나라도 fetch되고 있는 것을 파악하고 싶다면 global 변수로 useIsFetching을 사용하면 된다.
import { useIsFetching } from 'react-query';
const isFetching = useIsFetching()
Query Retries
useQuery가 실패하면 react-query는 자동으로 재시도를 한다. default로 3번 재시도를 하는데, 재시도 횟수는 retry 옵션을 이용하여 재설정할 수 있다.
useQuery(['todos', 1], fetchTodoListPage, {
retry: 10, // Will retry failed requests 10 times before displaying an error
})
마찬가지로 retryDelay 옵션을 줘서 delay 시간을 조정할 수도 있다.
const result = useQuery('todos', fetchTodoList, {
retryDelay: 1000, // Will always wait 1000ms to retry, regardless of how many retries
})
Pagination
페이지네이션 구현은 쉽다.
const result = useQuery(['projects', page], fetchProjects)
하지만 이렇게 코드를 짜면 매번 새로운 query가 실행되기 때문에 success와 loading이 계속 반복되는 것을 확인할 수 있다.
keepPreviousData를 사용하면 다른 query라도 상태를 반복하지 않고 실행 가능하다. keepPreviousData를 true로 설정하면 된다.
- 다음 data를 받아오는 동안 이전의 데이터가 유지된다.
- data가 도착하면 이전의 data를 대체한다.
- isPreviousData로 이전 데이터인지 확인할 수 있다.
const [page, setPage] = React.useState(0)
const fetchProjects = (page = 0) => fetch('/api/projects?page=' + page).then((res) => res.json())
const {
isLoading,
isError,
error,
data,
isFetching,
isPreviousData,
} = useQuery(['projects', page], () => fetchProjects(page), { keepPreviousData : true })
return (
<div>
{isLoading ? ( // 로딩중
<div>Loading...</div>
) : isError ? ( // 에러
<div>Error: {error.message}</div>
) : (
<div>
{data.projects.map(project => (
<p key={project.id}>{project.name}</p>
))}
</div>
)}
<span>Current Page: {page + 1}</span>
<button
onClick={() => setPage(old => Math.max(old - 1, 0))}
disabled={page === 0}
>
Previous Page
</button>{' '}
<button
onClick={() => {
if (!isPreviousData && data.hasMore) { // 데이터가 더 있고, 데이터가 불러와진 상태이면
setPage(old => old + 1)
}
}}
// Disable the Next Page button until we know a next page is available
disabled={isPreviousData || !data?.hasMore}
>
Next Page
</button>
{isFetching ? <span> Loading...</span> : null}{' '} // 다시 받아오는 중
</div>
)
- useInfiniteQuery hook과 함께 사용할 수도 있다.
'웹 (WEB) > 공부' 카테고리의 다른 글
React-query :: Query Invalidation (0) | 2021.07.10 |
---|---|
React-query :: Mutations (0) | 2021.07.10 |
DeepLink란? :: 원링크, 딥링크, 디퍼드 딥링크 (4) | 2021.07.10 |
JavaScript 동작 원리 :: 런타임 구성과 비동기 동작 (feat. 비동기 콜백) (0) | 2021.04.01 |
[React] React 환경변수, 개발 및 배포 시에 어떻게 사용할까? (Docker, github action 사용 시) (0) | 2021.03.14 |
Comment