정리를 하게 된 계기는 Query를 사용하고 있었고, 사용했었고 어떻게 흘러가는지 알고 있다고 생각했다. 하지만 설명을 하라고 하면 정확하게 내가 알고 있는대로 설명할 수 없는 나를 보고 이건 모르는것이다. 라고 생각하게 되었고, 정리를 통해서 설명해보려고 한다.
React-Query 이점
우리가 React-Query를 사용하는 이유는 데이터 조회, 캐싱, 동기화, 업데이트 등 많은 이점이 있다는 것이다.
Query Refetching 조건
1. 런타임에 stale인 특정 쿼리 인스턴스가 다시 만들어졌을 때
2. window가 다시 포커스가 되었을때(옵션으로 조절가능)
3. 네트워크가 다시 연결되었을때(옵션으로 조절가능)
4. refetch interval이 있을때 요청 실패한 쿼리는 디폴트로 3번 더 백그라운드단에서 요청하며, retry, retryDelay 역시 옵션으로 간격과 횟수를 커스텀 가능
Query API
Dependent Query : 쿼리가 동기적으로 실행해야 하는 경우 , useQuery의 옵션 중 enabled를 사용
function App(){
const { data: user } = useQuery(['user', email], getUserByEmail);
const userId = user?.id
const { isIdle, data: projects } = useQuery(
['projects', userId],
getProjectsByUser,
{
// 해당 query는 userId가 존재할때까지 실행되지 않는다.
enabled: !!userId,
}
)
}
enabled option을 통해 특정 data가 존재하면 Query가 시작하도록 설정 가능. (그 전까지 해당 query의 isIdle 값은 true)
Background fetching indicator : 특정 query가 background에서 fetching될 때의 값은 isFetching을 통해 확인
function Todos() {
const { status, data: todos, error, isFetching } = useQuery(
'todos',
fetchTodos
)
return status === 'loading' ? (
<span>Loading...</span>
) : status === 'error' ? (
<span>Error: {error.message}</span>
) : (
<>
{isFetching ? <div>Refreshing...</div> : null}
<div>
{todos.map(todo => (
<Todo todo={todo} />
))}
</div>
</>
)
}
** 모든 Query에 대한 refetching을 체크하고 싶을때는, useIsFetching hook을 사용
import { useIsFetching } from 'react-query'
function GlobalLoadingIndicator(){
const isFetching = useIsFetching();
return isFetching ? (
<div> Queries are fetching in the background...</div>
) : null
}
Query Retries : 아무 옵션도 주지 않았을 시 React Query는 기본적으로 3회 retry를 진행. (option 값을 변경함으로써 수정 가능)
import { useQuery } from 'react-query'
const result = useQuery(['todos', 1], fetchTodoListPage, {
retry: 10, // error를 띄우기 전 10번 retry 한다.
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
})
Paginated / Lagged Queries : 전에 Query된 데이터가 존재할때, 기존 데이터를 우선적으로 보여주고 background에서 데이터를 갱신하고 싶다면 옵션중에 keepPreviousData 이용
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 })
이 옵션은 페이지네이션을 구현할 때 유용하게 사용할 수 있다. 캐시되지 않은 페이지를 가져올 때 화면에서 목록이 사라지는 깜빡임 현상을 방지할 수 있다.
useMutation : useMutation hook의 경우 server side query에 사용한다. 즉, 데이터 생성/갱신/삭제에 해당하는 query에 사용한다.
function App() {
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
<div>
{mutation.isLoading ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
<button
onClick={() => {
mutation.mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
}
주로 mutate로 데이터 추가/삭제/갱신 작업을 진행 후 invalidQuries로 기존 조회에 사용했던 query를 무효화함으로써 자동 데이터 갱신을 진행할 수 있다.
import { useMutation, useQueryClient } from 'react-query'
const queryClient = useQueryClient()
// mutation 성공 시 onSuccess callback 실행됨
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos')
queryClient.invalidateQueries('reminders')
},
})
마무리
몰랐었던 리액트 쿼리의 옵션들에 대해서도 알게되었고, 그 옵션의 역할에 대해서도 알게 되었다. 실전에서 조금 더 사용해 볼 수 있는 옵션들을 많이 알게 되었다!
참고 할 사이트
https://velog.io/@seeh_h/React-query#query-retries
https://tkdodo.eu/blog/practical-react-query
https://velog.io/@kimmiri235/React-Query%EB%A5%BC-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90
'TIL' 카테고리의 다른 글
Git commit, 원격 repo, .gitignore (2) | 2024.06.14 |
---|---|
설계 단계_아키텍처 설계 (0) | 2024.05.10 |
[React] React에서 모달을 활용한 날짜와 시간 선택 관리하기 (0) | 2023.11.12 |
TypeScript를 활용한 안전한 클라이언트-서버 통신 및 인증 관리 (0) | 2023.11.10 |
마크다운 사용 (0) | 2023.11.10 |