
각 페이지에서 공통적으로 사용하는 전역 상태 데이터를 주로 redux를 이용해 처리했다. 프로젝트가 작을때는 괜찮았지만 프로젝트가 점점 커짐에 따라 관리해야할 데이터가 많아져 너무 복잡해졌다.
또한 프론트엔드 개발에서는 api통신을 빼놓을 수가 없는데 비동기 데이터관리가 용이해 사용하게 되었다.
✔️데이터 캐싱처리가 편해졌다.
✔️에러핸들링이 더욱 편해졌다.
✔️여러 컴포넌트에서 동시에 데이터가 필요한 경우 처리가 편해졋다
✔️구조가 redux를 사용할때보다 단순해졌다.
✔️직접 만들어서 쓰던 기능들이 react-query에서는 옵션으로 지원하기 때문에 사용성이 좋았다.
✔️infinity query 기능을 지원해 infinity scroll을 캐싱처리를 하면서 간단하게 구현이 가능했다.
react-query를 사용하기전에는 redux에 의존했다. react-query를 사용한 뒤
Redux로는 전역 상태 관리를하고 react-query로는 서버에서 받아온 데이터를 관리를 하게 되었다.
const UserWallet = () => {
const { isLoading, isError, data: Get_Wallet_list, error } = useQuery(["walletList", page],
async () => {
const { data } = await axios.get(process.env.REACT_APP_SERVER_URL + `/wallet`);
return data;
},
{
staleTime: 1000 * 60 * 60,
cacheTime: 1000 * 60 * 60,
refetchOnWindowFocus: false,
placeholderData: {},
retry: 0,
onSuccess: (data) => {
console.log(data);
},
onError: (e) => {
console.log(e.message);
},
}
);
if (isLoading) return <div> 로딩중... </div>;
if (error) return <div> 에러: {error.message} </div>;
return (생략);
}
"walletList", page 쿼리 인스턴스가 mount ->
데이터 fetch 후 "walletList", page라는 query key로 캐싱 ->
데이터는 fresh 상태에서 staleTime(기본값 0) 이후 stale 상태로 변경 ->
"walletList", page 쿼리 인스턴스가 unmount ->
캐시는 cacheTime(기본값 5min) 만큼 유지되다 가비지 콜렉터로 수집 ->
cacheTime이 지나기 전에 "walletList", page 쿼리 인스턴스가 mount되면 fetch가 실행되고 fresh 값을 가져오는 동안 캐시 데이터를 보여줌
✔️브라우저에 focus가 되었을 경우 (refetchOnWindowFocus)
✔️새로 mount가 되었을 경우 (refetchOnMount)
✔️네트워크가 끊어졌다가 다시 연결된 경우 (refetchOnReconnect)
✔️React-Query 는 캐싱 된 데이터는 항상 stale 하다고 판단하며, stale 상태인 데이터를 Refetching 한다.
data
isLoading
isFetching
staleTime
React-Query 는 데이터를 fetching 해온 후 데이터를 캐싱 하며 데이터가 stale 하다고 판단될 때 데이터를 refetching 하게 된다.
데이터가 fresh 에서 stale 상태로 변경되는데 걸리는 시간이 staleTime타임이다.
cacheTime
refetchOnWindowFocus
placeholderData
retry
onSuccess
onError
옵션은 너무 많아 자주 사용하는것만 적어 놓았다 자세한 옵션은 공식문서를 참고하자
queryKey는 문자열과 배열을 넣을 수 있다. 쿼리 키는 캐싱처리를 쉽게 만들어준다. 쿼리 키가 다르면 캐싱도 별개이기 때문이다.
나는 쿼리 키를 이용해 페이징이나 검색 옵션등을 주로 처리했다.
useQuery(["walletList", 1], ...)
useQuery(["walletList", 2], ...)
이런식으로 "walletList", page를 Key로 사용하여 데이터를 캐싱 할 수가 있다.
다른 컴포넌트에서 "walletList", page를 Key로 사용한 useQuery Hook이 있다면 캐시된 데이터를 사용한다.
서버 데이터를 가져오는 것은 reactive하게 동작하는 useQuery를 사용하면 되겠지만, 서버 데이터 업데이트는 그런 방식으로 사용하기에는 적절하지 않다.
useQuery와는 다르게 create, update, delete(생성/수정/삭제) 에는 useMutation 을 사용한다
import { useMutation } from "react-query";
const loginMutation = useMutation(Api, {
onMutate: variable => {
console.log("onMutate", variable);
// variable : {Id: '', Password: ''}
},
onError: (error, variable, context) => {
},
onSuccess: (data, variables, context) => {
},
onSettled: () => {
console.log("완료");
}
});
const handle = () => {
loginMutation.mutate({ Id: id, Password:password });
};
useQuery와 동일하게 onSuccess, onError, onSettled 콜백을 전달할 수 있으며 거기에 더해 mutate를 호출했을 때 실행할 onMutate 콜백도 사용할 수 있다.
onMutate
onSettled
update후 다시 데이터를 get하고싶다면 성공 후 invalidateQueries를 해주면된다.
글 작성이나 댓글등을 작성하면 서버에서 댓글 목록을 다시 Get 해서 리스트를 받아와야 한다.
이와 같은 경우에는 staleTime이 지나기 전에 직접 쿼리를 무효화해서 새로운 데이터를 가져온다.
const mutation = useMutation(newTodo => axios.post('process.env.REACT_APP_SERVER_URL+/wallet', ...))
const queryClient = useQueryClient();
queryClient.invalidateQueries(); //모든 쿼리를 무효화한다.
queryClient.invalidateQueries(["walletList"]) //walletList로 시작하는 모든 쿼리를 무효화한다. ex) ["walletList", 1], ["walletList", 2], ...
queryClient.invalidateQueries(["walletList", 2]) // ['walletList', 1] 키를 가진 쿼리를 무효화한다.