https://www.udemy.com/course/react-query-react/?utm_source=adwords&utm_medium=udemyads&utm_campaign=WebDevelopment_Search_la.KR_cc.KR&utm_term=_._ag_153638105748_._ad_644611295650_._kw__._de_c_._dm__._pl__._ti_dsa-1939216851836_._li_1009834_._pd__._&matchtype=&gad=1
https://github.com/ssi02014/react-query-tutorial#%EC%BA%90%EC%8B%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A6%89%EC%8B%9C-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8
https://velog.io/@familyman80/React-Query-%ED%95%9C%EA%B8%80-%EB%A9%94%EB%89%B4%EC%96%BC
https://parang.gatsbyjs.io/react/2022-react-01/
https://wonsss.github.io/library/react-query/#isfetching-vs-isloading
개요
- react query는 클라이언트에서 서버 데이터 캐시를 관리한다.
- 서버로부터 데이터가 필요할때, axios를 사용하지 않고 react query 캐시를 요청한다.
- react query의 역할은 react query 클라이언트를 어떻게 구성했는지에 따라 해당 캐시의 데이터를 유지 관리하는 것이다.
- 데이터를 관리하는 것은 react query이지만 서버의 새 데이터로 캐시를 업데이트하는 시기를 설정하는 것은 사용자의 몫이다.
- key : data 형태로 관리한다.
- 추가 기능
- 서버에 대한 모든 쿼리의 로딩 및 오류 상태를 유지해주기 때문에 수동으로 할 필요가 없다.
- 사용자를 위해 데이터의 페이지 매김 또는 무한 스크롤이 필요한 경우 데이터를 조각으로 가져올 수 있는 도구를 제공한다.
- prefetch를 사용해서 미리 캐시에 데이터를 넣어둘 수 있다.
- 서버에서 데이터의 변이(mutation)이나 업데이트를 관리할 수 있다.
- 쿼리는 키로 식별되기 때문에 react query는 요청을 관리할 수 있고, 페이지를 로드하고 해당 페이지의 여러 구성 요소가 동일한 데이터를 요청하는 경우 react query는 쿼리를 단 한번만 보낼 수 있다.(중복 요청 제거)
- 재시도 관리 가능
- 성공하거나 오류가 났을 때를 구별해서 조치할 수 있도록 콜백 전달 제공
getting start
- install library
- create query client
- 쿼리와 서버의 데이터 캐시를 관리하는 클라이언트
- apply queryProvider
- 자녀 컴포넌트에 캐시와 클라이언트 구성을 제공하는 역할
- 이에 대한 값으로 사용될 query client가 필요
- useQuery 훅을 사용한다.
npm i @tanstack/react-query
npm i @tanstack/react-query-devtools
const queryClient = new QueryClient();
function App() {
return (
// provide React Query client to App
<QueryClientProvider client={queryClient}>
<div className="App">
<h1>Blog Posts</h1>
<Posts />
</div>
<ReactQueryDevtools/>
</QueryClientProvider>
);
}
Query의 상태
- fresh : 새롭게 추가된 쿼리 & 만료되지 않은 쿼리 ➜ 컴포넌트가 마운트, 업데이트되어도 데이터 재요청 ❌
- fetching : 요청 중인 쿼리
- stale : 만료된 쿼리 ➜ 컴포넌트가 마운트, 업데이트되면 데이터 재요청 ⭕️
- inactive : 스크린에서 사용하지 않고(비활성화), 특정 시간(cacheTime)이 지나면 가비지 컬렉터에 의해 제거
useQuery 사용법
const requestData = useQuery(쿼리 키, 쿼리 함수, 옵션);
- 쿼리 키 : 문자열 or 배열, 캐싱 처리에 있어서 중요한 개념
- 쿼리 키가 다르면 쿼리 함수가 같아도 캐싱을 별도로 관리한다.
- 쿼리 함수: Promise를 리턴하는 함수, ex) axios(), fetch()
- 옵션 : useQuery 기능을 제어
const fetchSuperHeroes = () => {
return axios.get('http://localhost:4000/superheroes');
};
// 방법2. 구조분해 O
const { data, isLoading, isFetching, isError, error } = useQuery('super-heroes', fetchSuperHeroes);
if(isLoading) {
return <h2>Loading...</h2>
}
if(isError) {
return <h2>{error.message}</h2> // Request failed with status code 404
}
- data : 서버 요청에 대한 데이터
- isLoading : 캐시가 없는 상태에서의 데이터 요청 중인 상태 (true / false)
- isFetching : 캐시의 유무 상관없이 데이터 요청 중인 상태 (true / false)
- isFetching이 isLoading보다 큰 개념이고 isLoading을 포함한다고 보면 된다.
- isError : 서버 요청 실패에 대한 상태 (true / false)
- 기본적으로 react-query는 세번의 재시도를 하고 이후에는 시도하지 않고 error로 처리한다.
- 3번 처리하고 문제가 있으면 true가 된다.
- error : 서버 요청 실패 (object)
옵션
default 옵션 문서 : https://tanstack.com/query/v4/docs/react/guides/important-defaults
- cacheTime
- 기본값 : 30000 -> 5분
- stale 상태에서 비활성 쿼리(화면에서 언마운트 된 쿼리)가 된 후, 캐시에서 제거될 때까지의 시간
- 언마운트된 후 어느 시점까지 메모리에 데이터를 저장하여 캐싱할 것인지를 결정
- 데이터가 inactive 상태일 때 캐싱된 상태로 남아있는 시간을 말한다.
- 쿼리 인스턴스가 unmount되면 데이터는 inactive 상태로 변경되며, 캐시는 cacheTime 만큼 유지된다.
- 이걸 cacheTime 만큼 유지시키는 이유는 쿼리 인스턴스가 다시 마운트되면 데이터를 fetch하는 동안 cacheTime이 지나지 않은 캐시 데이터를 보여준다.
- cacheTime이 지나면 가비지 콜렉터로 삭제가 된다.
const { data, isLoading } = useQuery('super-heroes', fetchSuperHeroes, { cacheTime: 3000 });
- staleTime
- 기본값 : 0
데이터가 fresh -> stale 상태로 변경되는데 걸리는 시간
- fresh 상태에서는 컴포넌트가 마운트, 업데이트가 되어도 재요청을 보내지 않으므로 API 요청 횟수를 줄일 수 있다.
- fresh 상태일때는 쿼리 인스턴스가 새롭게 mount 되어도 네트워크 fetch가 일어나지 않는다.
- 데이터가 한번 fetch 되고 나서 staleTime이 지나지 않았다면 unmount 후 mount 되어도 fetch가 일어나지 않는다.
- refetchOnMount : 컴포넌트 마운트시 새로운 데이터 패칭
- 기본값 : true
- false로 설정할 경우 마운트시 새로운 데이터를 가지고 오지 않는다.
- refetchOnWindowFocus : 브라우저 클릭 시 새로운 데이터 패칭
- 기본값 : true
- flase로 설정할 경우 브라우저가 포커스 되어도 데이터를 가지고 오지 않는다.
- refetchInterval : 지정한 시간 간격만큼 데이터 패칭
- 기본값 : 0
- 브라우저에 포커스가 없을 때 실행되지 않는다.
- refetchIntervalInBackground
- 기본값 : false
- 브라우저에 포커스가 없어도 refetchInterval에서 지정한 시간 간격만큼 데이터 패칭
- enabled
- 기본값 true
- 마운트 시 자동으로 쿼리를 실행한다.
- false로 설정하면 쿼리를 자동으로 실행하지 않는다.
- keepPreviousData
- 기본값 false
- 쿼리 키(ex 페이지 번호)가 변경되어 새로운 데이터를 요청하는 동안 마지막으로 성공한 데이터로 유지된다.
- 이후 해당 쿼리 요청이 성공하면 이전 데이터를 성공한 값으로 변경한다.
- isPreviousData를 통해 현재 쿼리가 제공하는 데이터가 이전 값인지도 확인할 수 있다.
- onSuccess : 데이터 패칭 성공
- onError : 데이터 패칭 실패
- select : 데이터 패칭 성공 시 원하는 데이터 형식으로 가공
prefetching
- 페이징할때, 다음 혹은 이전 데이터를 미리 가져와서 캐시해두는 것을 예시로 들 수 있다.
- prefetch한 데이터는 stale 상태이고 실제로 데이터를 가져오는 도중에는 해당 데이터를 사용하고 가져오고나면 교체한다.(물론 cacheTime을 지나면 안된다.)
const queryClient = useQueryClient();
useEffect(() => {
if (currentPage < maxPostPage) {
const nextPage = currentPage + 1;
queryClient.prefetchQuery(['posts', nextPage], () =>
fetchPosts(nextPage),
);
}
}, [currentPage, queryClient]);
useIsFetching
- 현재 데이터를 가져오고 있는 중인 쿼리가 있는지 알려준다.
- 즉, 각각에 대한 isFetching을 사용할 필요성을 제거해준다.
const isFetching = useIsFetching();
useMutation
const requestData = useMutation(API 호출 함수, 콜백);
- POST, PUT, DELETE와 같은 변경 및 수정작업을 할때 사용되는 훅
- API 호출 함수: 특정 endpoint로 요청을 보내고 Promise를 반환하는 함수
- 콜백 : 라이프사이클에 따라 로직 작성
const mutation = useMutation(({ title, body }) => updateTodo(title, body))
mutation.mutate({ title: 'hello', body: 'world' })
- mutation 인자가 1개 이상일 경우에는 object 형식을 사용해야 한다.
import { useMutation, useQueryClient } from 'react-query';
const AddSuperHero = () => {
✅ const queryClient = useQueryClient();
const addSuperHero = (hero) => {
return axios.post('http://localhost:4000/superheroes', hero);
};
const { mutate: addHero, isLoading, isError, error } = useMutation(addSuperHero, {
onSuccess: () => {
// 캐시가 있는 모든 쿼리 무효화
✅ queryClient.invalidateQueries();
// queryKey가 'super-heroes'로 시작하는 모든 쿼리 무효화
✅ queryClient.invalidateQueries('super-heroes');
}
});
const handleAddHeroClick = () => {
const hero = { 이름, 성별 };
addHero(hero);
};
if (isLoading) {
return <h2>Loading...</h2>;
}
if (isError) {
return <h2>{error.message}</h2>;
}
}
useQuery와 같은 반환값을 받으며 mutate 메서드가 추가된다.
mutate 메서드를 이용하면 API 요청 함수를 호출하여 요청이 이루어진다.
업데이트 이후에는 기존 캐싱된 쿼리 무효화(Invalidation)를 시켜주고 새로 패칭해야한다.
mutate 함수가 실행되기 전, 성공 여부, 끝과 같이 라이프사이클에 따라 콜백함수를 작성할 수 있다.
useMutation(addSuperHero, {
onMutate: (variables) => {
// mutate 함수가 실행되기 전에 실행
console.log(variables) // addSuperHero에 들어가는 인자
},
onSuccess: (data, variables) => {
// 성공
},
onError: (error, variables) => {
// 에러 발생
},
onSettled: (data, error, variables, context) => {
// 성공 or 실패 상관 없이 실행
},
})
캐시 업데이트
invalidateQueries
const queryClient = useQueryClient();
queryClient.invalidateQueires([key1, key2])
// [key1, key2, key3] 로 쿼리키를 가지고 있는 쿼리도 제거된다.
- 쿼리를 무효화할 때 사용한다.
- invalidateQueries는 기본적으로 정확한 키를 입력받지 않고 prefix형태로 입력 받는다.
- 정확한 키를 입력받고 싶다면
{exact : true} 옵션을 사용해야 한다.
이렇게 캐시가 무효화되면 기본 옵션들에 의해 다음에는 쿼리를 새로 요청하게 될 것이다.
setQueryData
invalidateQueries는 쿼리를 무효화하고 기본 옵션들에 의해 다시 쿼리를 새로 요청하게 되는 형태로 플로우가 진행된다면 setQueryData를 사용하면 데이터를 즉시 업데이트 할 수 있다.
const useAddSuperHeroData = () => {
const queryClient = useQueryClient();
return useMutation(addSuperHero, {
onSuccess(data) {
queryClient.setQueryData(["super-heroes"], (oldData: any) => {
return {
...oldData,
data: [...oldData.data, data.data],
};
});
},
onError(err) {
console.log(err);
},
});
};
mutation을 사용해서 업데이트 시키고 전달받은 응답값을 사용해서 캐시 데이터를 내부적으로 업데이트 한다.(stale 상태)
타입스크립트
useQuery
https://parang.gatsbyjs.io/react/2022-react-06/
useMutationFunction 타입스크립트
useMutation을 훅으로 만들때는 반환 타입을 useMutationFunction을 사용한다.
에러 핸들링
문서 번역 : https://parang.gatsbyjs.io/react/2022-react-12/
client option으로 처리 : https://blog.hwahae.co.kr/all/tech/7867
바운더리 : https://tecoble.techcourse.co.kr/post/2021-10-01-react-query-error-handling/
인증 with axios
https://codevoweb.com/react-query-context-api-axios-interceptors-jwt-auth/
개요
getting start
Query의 상태
useQuery 사용법
옵션
const { data, isLoading } = useQuery('super-heroes', fetchSuperHeroes, { cacheTime: 3000 });데이터가 fresh -> stale 상태로 변경되는데 걸리는 시간prefetching
useIsFetching
useMutation
useQuery와 같은 반환값을 받으며 mutate 메서드가 추가된다.
mutate 메서드를 이용하면 API 요청 함수를 호출하여 요청이 이루어진다.
업데이트 이후에는 기존 캐싱된 쿼리 무효화(Invalidation)를 시켜주고 새로 패칭해야한다.
mutate 함수가 실행되기 전, 성공 여부, 끝과 같이 라이프사이클에 따라 콜백함수를 작성할 수 있다.
캐시 업데이트
invalidateQueries
{exact : true}옵션을 사용해야 한다.이렇게 캐시가 무효화되면 기본 옵션들에 의해 다음에는 쿼리를 새로 요청하게 될 것이다.
setQueryData
invalidateQueries는 쿼리를 무효화하고 기본 옵션들에 의해 다시 쿼리를 새로 요청하게 되는 형태로 플로우가 진행된다면 setQueryData를 사용하면 데이터를 즉시 업데이트 할 수 있다.
mutation을 사용해서 업데이트 시키고 전달받은 응답값을 사용해서 캐시 데이터를 내부적으로 업데이트 한다.(stale 상태)
타입스크립트
useQuery
useMutationFunction 타입스크립트
useMutation을 훅으로 만들때는 반환 타입을 useMutationFunction을 사용한다.
에러 핸들링
인증 with axios