FrontEnd/React
[React] React-Query의 개념 및 예제
검정색필통
2023. 3. 2. 11:27
React Query는 API 통신과 비동기 데이터 관리에 사용되는 React 라이브러리 입니다.
1. React-Query 이전
- state에 비동기 데이터를 보관할 경우
- 다수의 component의 lifecycle에 따라 비동기 데이터가 관리되기 때문에 캐싱 등 최적화를 하기 어려움
- 다수의 component에서 동일한 API를 호출하거나, 특정 API응답이 다른 API에 영향을 미치는 경우 등에 대응하기 어려움
- Redux를 사용하여 비동기 데이터를 관리할 경우
- componet의 lifecycle과 관계없이 비동기 데이터를 관리할 수 있어 최적화가 쉬우며 복잡한 사용자 시나리오에도 대응 가능
- 장황한 Boilerplate 코드로 인해 비동기 Action 처리에 복잡성 증가
- Redux는 API 통신 및 비동기 상태 관리를 위한 라이브러리가 아니라 Global State Management Library, 즉 전역 상태 관리 라이브러리이기 때문에 API 요청 수행을 위한 규격화된 방식 부재
- 사용자 경험 향상을 위한 복잡한 시나리오를 수행하는데 많은 개발 리소스 소모
2. React-Query란?
- React Application에서 서버의 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트 하는 작업을 도와주는 라이브러리
- 우리에게 친숙한 Hook을 사용하여 React Component 내부에서 자연스럽게 서버(또는 비동기적인 요청이 필요한 Source)의 데이터를 사용할 수 있는 방법을 제안
- API 요청을 Query 그리고 Mutation 이라는 두 가지 유형으로 나누어 생각
3. Query 요청 개요
const { status, data, error } = useQuery(
queryKey, // 이 Query 요청에 대한 응답 데이터를 캐시할 때 사용할 Unique Key (required)
fetchFn, // 이 Query 요청을 수행하기 위한 Promise를 Return 하는 함수 (required)
options, // useQuery에서 사용되는 Option 객체 (optional)
);
- status
- isLoading or status === 'loading' - 데이터가 없거나 아직 fetch 중일 때
- isError or status === 'error' - 데이터를 불러오는 과정에서 error를 호출할 때
- isSuccess or status === 'success' - 성공적으로 데이터를 불러왔을 때
- isIdle or status === 'idle' - The query is currently disabled (you'll learn more about this in a bit)... 잘 모르겠음..?
- error
- isError state에 도달 하면 반환하는 객체
- data
- isSuccess state에 도달하면 반환하는 객체(데이터)
- isFetching
- 아직 query가 진행 중이면 isFetching은 true를 반환
4. Query Key
- Query Key는 string이거나 string이나 nested object로 이루어진 배열로, Query Key를 통해 React Query는 데이터를 캐싱하고 관리한다.
// string query keys
useQuery('todos', ...) // queryKey === ['todos']
// array query keys
useQuery(['todo', 5], ...) // queryKey === ['todo', 5]
useQuery(['todo', 5, { preview: true }], ...) // queryKey === ['todo', 5, { preview: true }]
useQuery(['todos', { type: 'done' }], ...) // queryKey === ['todos', { type: 'done' }]
// array key에서 순서가 바뀌면 다른 키
// ex) 같은 키
useQuery(['todos', { status, page }], ...)
useQuery(['todos', { page, status }], ...)
// ex) 다른 키
useQuery(['todos', status, page], ...)
useQuery(['todos', page, status], ...)
// variable이 바뀔 경우에 query를 호출 하고 싶으면 query key에 variable을 담는다. (변수 의존)
function Todos({ todoId }) {
const result = useQuery(['todos', todoId], () => fetchTodoById(todoId))
}
5. Query Function
promise를 반환하는 fuction으로 비동기 요청으로 받은 데이터나 에러를 반환한다.
// 다음과 같은 방법 모두 사용 가능하다.
useQuery(['todos'], fetchAllTodos)
useQuery(['todos', todoId], () => fetchTodoById(todoId))
useQuery(['todos', todoId], async () => {
const data = await fetchTodoById(todoId)
return data
})
useQuery(['todos', todoId], ({ queryKey }) => fetchTodoById(queryKey[1]))
6. useQueries
useQuery의 호출 수가 render마다 바뀌는 경우, hook rule을 위반하기 때문에 수동으로 useQuery를 사용할 수 없다. 이때 useQueries를 사용하여 동적으로 query를 호출한다.
function App({ users }) {
const userQueries = useQueries(
users.map(user => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
})
)
}
React.Suspense모드를 사용할 때도 suspense = true를 적용하여 로딩 상태 처리를 useQuery에서 처리하지 않도록 할 수 있다.