Just Do IT!
[React] React Query 본문
728x90
반응형
React Query를 사용하는 이유?
- 원래 다른 서버와의 API 통신과 비동기 데이터 관리를 위해 Redux-thunk, Redux-Saga 등 미들웨어를 사용했었다.
- 클라이언트 쪽의 데이터들을 관리하기에 적합해도 서버 쪽의 데이터들을 관리하기에는 적합하지 않아서 불편한 점이 있엇다. (Redux는 비동기 데이터 관리를 위한 전문 라이브러리가 아니다)
- 서버 데이터와 클라이언트 데이터 분리에 용이하다.
- React Query 라이브러리를 사용하면 편리하다.
서버 데이터와 클라이언트 데이터
- 서버 데이터
- 여러 사람들이 동시에 공유할 수 있는 데이터
- 서버라는 공간에서 계속 쓰이는 데이터를 뜻한다.
- 특정 시점에 클라이언트의 요청에 대해 데이터 베이스에서 유저 정보를 가져와 서버의 상태 값을 만들어낸다
- 데이터 베이스에 있는 값을 그대로 클라이언트에게 전달 할 수도 있고, 요청에 담긴 특정 값을 이용해 정보를 가공 해서 메모리에 들고 있는다
- 이러한 정보를 클라이언트에게 제공한다.
- 클라이언트 데이터
- client에서 자체적으로 만드는 state (최초 데이터의 발생지가 클라이언트)
- server에서 전달받은 값으로 만다는 state (최초 데이터의 발생지가 서버)
- 사용자의 편의성을 위해 관리가 필요한 데이터를 뜻한다.
☞ React Query는 서버에서 가져온 데이터를 웹 브라우저 앱에서 사용하기 쉽게 도와주는 기술이다
React Query 설치
$ npm i react-query --save
$ yarn add react-query
공식문서에서 제공하는 Quick Start
import {
useQuery,
useMutation,
useQueryClient,
QueryClient,
QueryClientProvider,
} from 'react-query'
import { getTodos, postTodo } from '../my-api'
// Create a client
const queryClient = new QueryClient()
function App() {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
)
}
function Todos() {
// Access the client
const queryClient = useQueryClient()
// Queries
const query = useQuery('todos', getTodos)
// Mutations
const mutation = useMutation(postTodo, {
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries('todos')
},
})
return (
<div>
<ul>
{query.data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
<button
onClick={() => {
mutation.mutate({
id: Date.now(),
title: 'Do Laundry',
})
}}
>
Add Todo
</button>
</div>
)
}
render(<App />, document.getElementById('root'))
- useQuery, useMutation 등 다양한 hook을 제공한다.
- 기존에는 state 관리가 필요했지만 react query에서는 필요하지 않다.
useQuery()
- 어떤 데이터에 대한 요청을 의미한다
- axios의 경우 get 요청과 비슷하다.
- 첫 번째 인자 : Query Keys
- refetching하는데 쓰임
- 애플리케이션 전체 맥락에서 이 쿼리를 공유하는 방버으로 쓰임
- 어떤 컴포넌트에서도 같은 key면 같은 쿼리 및 데이터 보장
- 한 단어, 배열, 객체 등이 key가 될 수 있다 (unique해야 한다)
- api 로직과는 전혀 관계 없다
- 두 번째 인자 : Query Function (쿼리 함수)
- 쿼리 함수는 promise 객체를 return 한다
- promise 객체에 담기는 주요한 상태 정보
- 대기 (pending) : 요청한 직후 아직 성공(resolve) 혹은 실패(rejected)되지 않은 상태
- 이행 (fulfilled) : 정상적으로 전달을 해준 상태
- 거부 (rejected) : 데이터를 전달 못해준 상태
- promise 객체는 반드시 data를 resolve 하거나 error를 발생시킨다.
- useQuery를 통해 얻은 결과물은 객체(Object)이다
- 그 안에는 '조회'를 요청한 결과에 대한 거의 모든 정보가 들어 있다.
- 시작하면 isLoading = true
- 조회 결과 오류 발생 : isError = true / isLoading = false
- 조회 결과 정상 : isSuccess = true / isLoading = false (data 객체를 통해 좀 더 상세한 조회 결과 확인)
- 예제 (todo)
import { useQuery } from 'react-query';
function TodoList({ isActive }) {
const { isLoading, isError, data, error } = useQuery(['todos';, { isDone: isActive }], getTodos);
if (isLoading) {
return <p>로딩중입니다</p>;
)
if (isError) {
console.log("error : ", error);
return <p>오류가 발생하였습니다</p>;
)
...
useQueries()
- 여러 개의 useQuery를 쓰고 싶을 때 useQuery를 사용하면 다른 쿼리가 실행되기 전에 첫번째 쿼리가 중단하고 에러를 반환할 수 있다.
- 여러개의 useQuery를 나란히 사용할 수 있다
- Query Option 객체를 배열로 받을 수 있고, 마찬가지로 결과값 또한 배열로 return 해준다.
function App({ users }) {
const userQueries = useQueries(
users.map(user => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
})
)
}
useMutation
- 어떤 데이터(=데이터의 그룹)를 변경
- 추가, 수정, 삭제가 가능하다는 의미
- axios의 post, put, patch, delete 요청과 비슷하다
- useMutation()의 첫번째 인자인 mutationFn는 필수이다
- optimistic update을 활용해서 미리 UI부터 갱신할 수 있다
- invalidateQueries 메소드 및 setQueryData 메소드랑 같이 사용하면 최고의 효율을 낼 수 있다.
- invalidateQueries : 원래의 data 대신 data를 갱신해서 가져올 수 있다
- setQueryData : 기존에 queryKey에 매핑되어 있는 데이터를 새롭게 정의해준다 (invalidateQueries 사용 안해도 된다)
- Option
- onMutate: (variables) => Promise
- mutation() 이 실행하기 전 먼저 실행되고 mutation()함수가 전달받은 파라미터가 동일하게 전달됩니다.
- onSuccess: (data, variables, context) => Promise
- mutation()이 성공하면 결과를 전달할 때 실행 됩니다.
- onError: (err, variables, context) => Promise
- mutation()과정에서 에러가 발생되면 실행됩니다.
- onSettled: (data, error, variables, context) => Promise
- mutation()의 성공 / 에러 상황에 따라 해당 데이터를 전달받습니다.
- onMutate: (variables) => Promise
- 예제
import { QueryClient, useMutation } from 'react-query';
function Input() {
...
const queryClient = new QueryClient();
const mutation = useMutation(addTodo, {
onSuccess: () => {
// Invalidate and refresh
// 이렇게 하면 todos라는 이름으로 읽었던 data가 최신이 아니므로 invalidate할 수 있음
// TodoInput.jsx 파일의 useQuery의 querykey 이름으로 데이터를 갱신해서 가져옴
queryClient.invalidateQueries('todos'); // 서버데이터에 의존하고 있음
}
...
// 삭제하는 부분
const removeTodoMutation = useMutation(removeTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos');
},
});
...
React Native 강의를 들으면서도 정리했었는데 그거는 native에서 사용하는 거라 조금 다른 것 같아서
아예 특강도 들은 겸 따로 글로 정리해봤다.
이외의 내용들은 나중에 공부하면서 추가하거나 공식 문서에서 보면 될 듯 하다.
https://react-query-v3.tanstack.com/
728x90
'개발 공부 > React' 카테고리의 다른 글
[React] react Icons(리액트 아이콘) 사용하기 (0) | 2023.01.28 |
---|---|
[React] React-slick 라이브러리 사용하기 (0) | 2023.01.24 |
[React] Vercel(react) / Glitch(json-server) 배포하기 (0) | 2023.01.05 |
[React] 스파르타코딩 내일배움캠프 React 심화 내용 정리 (0) | 2022.12.21 |
[React] react-toastify 사용하기 (0) | 2022.12.19 |