리액트와 리덕스를 사용해 상태를 관리하다 보면 서버의 상태 또한 관리를 해줘야 할 경우가 생기는데
리덕스 덕분에 전역적으로 상태를 관리할 수 있게 되었지만 서버의 데이터를 리덕스를 통해서 관리하다보면 클라이언트 데이터와 서버의 데이터가 공존하게 되는 경우가 생겼다.
이 경우 클리이언트 데이터와 서버의 데이터가 서로 상호작용하면서 동작하는 경우도 분명 있을 텐데, 양쪽의 데이터를 최신 상태로 맞춰주는 과정과 최신 상태가 맞는지에 대한 확인도 하게되어서 불편한 부분이 많았다.
이를 해결하기 위해
*비동기 과정을 선언적으로 관리
*서버에서 받아온(get) 데이터가 업데이트되면 자동으로 다시 get을 수행
데이터가 최신이 아니라고 판단되면 다시 가져옴(get) | invalidateQueries
서버의 데이터를 관리하기가 편함
사용하기 쉬움
많은 장점이 있겠지만 현재 상황에서 가장 마음에 들었던 부분은 서버의 데이터를 따로 관리할 수 있다는 점과 비동기 요청을 선언적으로 관리하기가 편하다는 점이였다.
위 장점 뿐만 아니라 더 많은 기능들을 가지고 있어 사용하면서 천천히 익혀갈 생각이다.
// src/index.js
import { QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";
const queryClient = new QueryClient();
ReactDOM.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
{/* devtools */}
<ReactQueryDevtools initialIsOpen={true} />
<App />
</QueryClientProvider>
</React.StrictMode>,
document.getElementById("root")
);
리덕스와 비슷하게 초기 세팅을 해준다.
*get으로 데이터를 가져오기 위한 api입니다.
첫번째 파라미터로 unique key가 들어가며, 두번째 파라미터로 promise가 들어가는 비동기 (api 호출)함수가 들어갑니다.
*첫번째 파라미터로 설정한 unique key는 다른 컴포넌트에서도 해당 키를 사용하여 호출할 수 있습니다.
string
혹은 배열
을 받습니다.return 값은 api의 성공/실패 여부, api return 값을 포함한 객체
*useQuery는 비동기
로 작동합니다.
enabled를 사용하면 동기적으로도 사용할 수 있습니다.
const Todos = () => {
const { data, status, error } = useQuery("todos", fetchTodoList, {
refetchOnWindowFocus: false,
retry: 0,
onSuccess: data => {
// 성공시 호출
console.log(data);
},
onError: e => {
// 실패시 호출
console.log(e.message);
}
});
if (status === "loading") {
return <span>Loading...</span>;
}
if (status === "error") {
return <span>Error: {error.message}</span>;
}
return (
<ul>
{status === "success" && data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
refetchOnWindowFocus : 사용자가 사용하는 윈도우가 다른 곳을 갔다가 다시 화면으로 돌아오면 이 함수를 재실행합니다. 그 재실행 여부 옵션 입니다. | default: true
retry : 요청 실패시 재호출 몇번 할지 설정합니다. | default: 3
false
- 재시도가 비활성화됩니다.true
- 실패한 요청을 무한히 재시도합니다.(failureCount, error) => ...
사용하면 요청이 실패한 이유에 따라 맞춤 논리를 사용할 수 있습니다.onSuccess: data => {
// 성공시 호출
console.log(data);
},
위 옵션의 호출 성공은 api 요청에 대한 성공입니다.
즉, 상태 코드 200번 등의 반환으로 데이터를 받아오는 것을 성공한것도,
상태 코드 4~500번 등의 반환으로 에러를 받아오는 것도
모두 onSuccess에 해당합니다.
위와 같은 이유로
onError: e => {
// 실패시 호출
console.log(e.message);
}
위와 비슷한 맥락으로 401, 404 같은 error가 아니라 정말 api 호출이 실패한 경우만 호출됩니다.
강제로 에러 발생시키려면 api단에서 throw Error 날립니다.
생산성을 높이기 위해 알아야 할 몇 가지 매우 중요한 상태가 포함되어 있습니다.
쿼리는 특정 순간에 다음 상태 중 하나
만 있을 수 있습니다.
isLoading
또는 status === 'loading'
- 쿼리에 아직 데이터가 없습니다.
isError
또는 status === 'error'
- 쿼리에 오류가 발생했습니다.
isSuccess
또는 status === 'success'
- 쿼리가 성공했고 데이터를 사용할 수 있습니다.
쿼리가 제공하는 위 상태를 통해서 로딩 / 에러 / 성공에 대한 데이터 처리를 보다 쉽게 작성할 수 있습니다.
보다 자세한 상태에 대한 정보는 👈
쿼리가 자동으로 실행되지 않도록 하려면 enabled = false
옵션을 사용하면 됩니다.
enabled 옵션을 사용하면 useQuery를 동기적으로 사용 가능합니다.
const { data: todoList, error, isFetching } = useQuery("todos", fetchTodoList);
const { data: nextTodo, error, isFetching } = useQuery(
"nextTodos",
fetchNextTodoList,
{
enabled: !!todoList // true가 되면 fetchNextTodoList를 실행
}
);
useQuery의 3번째 인자로 옵션값을 넣어줄 수 있으며, enabled : true
로 로직을 구성하면 실행시킬 수 있습니다.