서버상태 관리를 위한 라이브러리
데이터를 패칭하고 캐싱, 동기화, 무효화 등의 기능을 제공
이전보다 비동기 로직을 간편하게 작성하고 유지보수성을 높일 수 있음
주요 기능
1) 데이터 캐싱: 동일한 데이터를 여러번 요청하지 않도록 캐싱하여 성능을 향상시킴
2) 자동 리페칭: 데이터가 변경되었을 때 자동으로 리페칭하여 최신상태를 유지
3) 쿼리 무효화: 특정 이벤트가 발생했을 때 쿼리를 무효화하고 데이터를 다시 가져올 수 있음
사용해보기
주요 hooks
1) get: useQuery
2) modify: useMutation
3) refresh: invalidateQueries
설치
yarn add @tanstack/react-query
Provider
QueryClientProvider로 서버상태의 영향권에 들어올 App 컴포넌트 등을 감싸준다
client 속성으로 기능 집합체인 인스턴스를 전달해줘야 함
const queryClient = new QueryClient();
<QueryClientProvider client={ queryClient }>
<App/>
</QueryClientProvider>
useQuery()
두 인자를 전달 -> queryKey, queryFn
이런 처리도 가능해짐
useMutation()
변화가 생겨서 update해야할 때 어떤 동작을 해야할지 지정해줘야 함
1) useMutation 훅을 이용해 mutation 객체를 만든다
2) addTodo 로직을 추가하고, mutation.mutate로 사용
- newTodo는 input value를 제어하고있는 state
* ) 혹은 구조분해 할당으로 mutation.mutate를 바로 받아둬도 됨
invalidateQueries()
위 과정까지만 진행했을 땐, 서버에는 새로운 데이터가 추가됐지만 우리 눈에 보이는 클라이언트는 아직 업데이트 되지 않음
따라서 refresh 과정인 invalidateQueries를 처리해줘야 함
1) 기존에 QueryClientProvider 레벨에서 만들어뒀던 queryClient를 useQueryClient()를 통해 받아온다
2) matate에서 onSuccess에 실행할 처리를 작성해준다 queryClient.invalidateQueries에는 queryKey를 배열형태로 넣어준다
-> 쿼리키는 데이터를 캐싱하는 기준, 이제 이 쿼리키가 더이상 유효하지 않다고 처리해주면서 현재 서버의 todos로 클라이언트를 갱신해주는 것
QueryClient의 동작 과정
useQuery()
- 캐시된 컨텍스트에 접근해서 값을 받아옴
- 아직 없을 땐 undefined
- 없으면 api 서버로 GET 요청
- 서버가 todos (해당하는 데이터)로 컨텍스트에 캐싱 처리
- 변경된 상태가 페이지 컴포넌트에 반영되기 전에 리렌더링이 일어남
- 리렌더링이 일어나면서 useQuery가 다시 실행되고, 이제는 컨텍스트에 캐시된 값이 있으니까 그 값이 반영됨
그 다음에 렌더링되는 컴포넌트에서 같은 queryKey에 대해 useQuery를 사용하는 경우, 이미 위의 과정에서 캐시된 데이터가 컨텍스트에 있기때문에 위의 과정을 거치지 않고 바로 컨텍스트에서 값을 받아올 수 있음 (isPending === true인 과정을 거치지 않음)
invalidateQueries()
- 이후 queryKey에 대한 refresh 요청이 일어났을 때, 다시 API 서버에 해당 값을 요청하고 컨텍스트에 서버의 새로운 값이 들어오면서 해당 값을 사용하고 있는 컴포넌트들에 새로운 값들이 반영됨
주요 흐름 설명
- A컴포넌트에서
- A 페이지 컴포넌트에서 useQuery가 실행됩니다. 이 때, todos 라는 Query Key를 기준으로 캐시 컨텍스트에 데이터를 요청해요.
- 최초 상태에는 todos라는 Query Key에 아무 값도 저장되어 있지 않기 때문에 const { data } = useQuery~~ 의 data는 undefined가 됩니다.
- 이후, getTodos(query function)을 호출하고, 실행이 완료되면 외부에서 가져온 todos 데이터를 캐시 컨텍스트 안에 담습니다. 이 과정을 위의 이미지에서는고 표현했네요.
- [”todos”]에 대한 데이터로 캐싱처리 한다
- A 페이지 컴포넌트에 값을 반영시키기 전에 re-rendering이 일어납니다.
- React 컴포넌트는 상태나 props가 변경되면 다시 렌더링되죠? useQuery hook 역시 데이터 패칭 상태가 변경될 때 컴포넌트를 다시 렌더링합니다. 데이터 패칭 상태는 곧 배워요 😎
- useQuery가 다시한번 실행되며, todos 라는 Query Key를 기준으로 캐시 컨텍스트에 데이터를 요청해요.
- 이제 캐싱된 데이터가 존재하기 때문에 값을 반환하여 const { data } = useQuery~~ 의 data에는 값이 담기게 됩니다.
- B컴포넌트에서
- B 페이지 컴포넌트에서 useQuery가 실행됩니다. 이 때, todos 라는 Query Key를 기준으로 캐시 컨텍스트에 데이터를 요청해요.
- 이미 캐싱된 데이터가 존재하기 때문에 값을 반환하여 const { data } = useQuery~~ 의 data에는 값이 담기게 됩니다.
- C컴포넌트에서
- C 페이지 컴포넌트에서 어떠한 액션에 의해 addTodo 라는 api 호출이 되며 데이터 갱신을 시도합니다.
- 성공적으로 완료되었습니다. 이 때, 자동으로 useQuery에서 썼던 캐시데이터가 갱신되지 않아요! 반드시 해당 queryKey를 기준으로 invalidateQueries 처리를 해줘야 기존에 가져왔던 오래된 데이터를 새 것으로 갈아끼게 됩니다.
- invalidateQueries 처리를 하게 되면, useQuery를 이용하여 캐시데이터를 활용했던 모든 곳이 새로운, fresh한 데이터를 구독하게 돼요.
'React' 카테고리의 다른 글
[React] Zustand (0) | 2024.09.06 |
---|---|
Tanstack Query 캐시데이터의 생명주기 (0) | 2024.09.05 |
[React] 비동기 작업, HTTP (0) | 2024.09.05 |
[React/supabase] 변경된 column만 업데이트하기 (0) | 2024.09.03 |
[React] react-router-dom Outlet 이동하지 않을 때 (0) | 2024.08.27 |