
https://portal.gitnation.org/contents/thinking-in-react-query
useQuery 훅을 써서 다양한 상태와 데이터를 랜더링하는데, 이 상황에서 React Query가 신경 쓰는건 fulfill됐거나 reject된 Promise의 리턴값뿐이다.useQuery({
queryKey: ['issues'], // 데이터를 저장하는 곳
queryFn: () => axios.get('/issues').then((response) => response.data), // 데이터를 받아오는 곳
});
// queryFn은 Promise를 리턴하는 함수라면 뭐든지 가능!
// **resolve the data** or **throw an error
* https://tanstack.com/query/v4/docs/react/guides/query-functions**
if(state === 'loading') return 'Loading...' // 상태에 따라 랜더링
return ( <ul>{data.map(......)}</ul> // 데이터 랜더링
React Query는 비동기적인 상태 관리 매니저(Async State Manager)이다.
- cf) "It's Time to Break Up with Your Global State" - Tanner Lindsley, 2020 → React Query의 창시자인 Tanner의 강연. 추천!
client state와 server state를 관리하는 방식의 구분이 필요하다.
상태는 이것이 어디서 사용되느냐가 아니라, 어떤 종류의 상태인지로 구분해야한다.


비동기적인 상태나 서버 상태의 경우, 우리는 데이터가 불러왔을 때의 상태(snapshot)만을 알 수 있다.
클라이언트에서 서버 상태를 갖지 않기 때문에 이 데이터는 오래된 데이터일 수 있다. 클라이언트는 단순히 어떤 시점의 상태(snapshot)만을 빌려와서 해당 데이터를 노출할 뿐이다.
상태는 동기적이지 않기 때문에, loading이나 error와 같은 상태 정보도 관리되어야 한다.
기존의 상태 관리 툴들은 데이터를 업데이트된 상태로 유지하거나 비동기적인 상태의 Lifecyle을 관리할 수 없고, React Query는 이러한 상태관리를 가능하게 해준다.
⇒ React Query는 비동기적인 상태 관리 매니저(Async State Manager)이다.
useSelector(state => state.xx) useStore(state => state.xx)function useIssues(select) {
return useQuery({
queryKey: ['issues'],
queryFn: () => axios.get('/issues').then((response) => response.data),
select, // 데이터를 정제하는 옵션
});
}
// * 'select' : QueryFuntion이 리턴하는 데이터를 정제해서 리턴시킬 수 있음.
// query cache에 저장되는 데이터에는 영향을 주지 않는다.
// `select: (data: TData) => unknown` : 함수형태로 세팅한다
*** https://tanstack.com/query/v4/docs/react/reference/useQuery**
function useIssueCount() {
return useIssues((issues) => issues.length); // **React Query의 Selector 방식**
}
// 'issues'가 변하면 'useIssueCount' 훅이 리턴하는 length 데이터도 업데이트됨.
// BUT!
// useIssueCount() 훅은 데이터 리스트의 length와 관련되어 있기 때문에,
// 만약 issue.isOpened 등의 다른 상태가 변경된 'issues' 데이터가 오더라도 length가 변하지 않았다면 useIssueCount 훅은 리랜더링되지 않는다!
useEffect 훅이나 v5 버전에서는 deprecated된 onSuccess 와 같은 기능은 필요하지 않다.
staleTimeuseQuery 콜함. 그런데 네트워크 요청이 단시간에 왜이렇게 많이 일어나지…? → refetch 관련 옵션과 retry를 모두 꺼봅니다… ok…. 하지만 이렇게 fetch되는 이유가 있지 않을까?staleTime → 데이터가 stale하게 되기까지의 시간 (stale = no longer fresh = 오래된, 낡은)staleTime 디폴트는 0이다staleTime은 정하기 나름이다. 정답은 없음!
staleTime: infinitystaleTime: 0 이 필요할 것.staleTime을 설정해두고, 필요하다면 쿼리마다 재설정하도록 세팅.
queryKey: ['get-issue-list', page]
useEffect 의 의존성 배열과 같다고 생각할 수 있다. 하지만 데이터 참조의 지속을 위해 useMemo 나 useCallback 를 쓸 필요가 없는 형태. → React Query가 알아서 데이터의 상태를 캐싱하고 관리하기 때문이다.useEffect(() => {
...
}, [ 의존성 배열(dependency array) ] // 의존성 배열 내의 요소가 변경되면 useEffect 훅이 동작한다.
)}
// QueryKey 역시 QueryKey 내의 파라미터 요소가 변경되면 데이터 갱신을 위해 QueryFn을 호출하지만, 데이터의 상태에 따라 알아서 캐싱하거나 데이터를 다시 불러오도록 조율함.
// * query의 staleTime에 따라 데이터가 낡았는지 여부를 판단
function useIssues() {
**const filters = useStore((state) => state.filters);**
return useQuery({
queryKey: ['issues', filters],
queryFn: () => {
const url = `/issues?filters=${filters}`;
return axios.get(url).then((response) => response.data);
},
});
}
// **filters는 client state 이므로 별도로 store 해두고 사용하면, filters 가 바뀔 때마다 query가 자동으로 돌거나 캐시에서 최근 데이터를 읽어올 것.**
// (server state는 useQuery를 통해 관리되는 것)staleTime 은 참 좋은 친구에용. 필요에 따라서 세팅해서 써야한다.