[React] React Query

상현·2023년 12월 3일
1

React

목록 보기
14/24
post-thumbnail

React Query란?

리액트 쿼리는 리액트에서 서버 데이터를 불러오고, 캐싱하고, 동기화를 편리하게 해주는 라이브러리이다.

리액트에서는 기본적으로 서버 데이터를 불러오는 방법을 따로 제공하지 않는다. 따라서 개발자가 직접 fetch같은 함수나 ajax, axios 같은 라이브러리를 이용하여 서버와 통신하고, 데이터를 사용 해야한다.

서버 데이터는 로컬에서 사용하는 데이터와는 다르다. 우리가 보는 데이터가 '오래된' 데이터일 수 있기 때문에 항상 최신 상태를 유지시켜줘야 한다.

따라서 기존에는 데이터를 서버에서 불러오고, 그 데이터를 전역 store에 담고, 그 store에 담긴 데이터를 컴포넌트에서 이용하고... 데이터가 업데이트 되면 다시 데이터를 불러오고 담고 쓰고.. 를 반복했다.

이러한 과정을 RTK와 Redux Thunk로 구현했을 때 다음과 같이 코드를 작성할 수 있다.

export const __findAllLetterByName = createAsyncThunk('letters/findAllByName', async arg => {
  const {data} = await letterApi.get(`/letters?to=${arg}`);
  return data;
});

// 생략....

const lettersSlice = createSlice({
  name: 'letters',
  initialState,
  extraReducers: builder => {
    builder
      .addCase(__findAllLetter.pending, (state, action) => {
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(__findAllLetter.fulfilled, (state, action) => {
        state.letters = action.payload;
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(__findAllLetter.rejected, (state, action) => {
        state.isLoading = true;
        state.isError = true;
        state.error = action.payload;
      })
      .addCase(__findAllLetterByName.fulfilled, (state, action) => {
        state.letters = action.payload;
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(__removeLetterById.pending, state => {
        state.isLoading = true;
        state.isError = false;
      })
      .addCase(__removeLetterById.fulfilled, (state, action) => {
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(__addLetter.pending, state => {
        state.isLoading = true;
        state.isError = false;
      })
      .addCase(__addLetter.fulfilled, (state, action) => {
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(__updateLetterById.pending, state => {
        state.isLoading = true;
        state.isError = false;
      })
      .addCase(__updateLetterById.fulfilled, (state, action) => {
        state.isLoading = false;
        state.isError = false;
      });
  },
});

Redux는 분명 전역 상태 관리 라이브러리인데... 이 코드를 보고 사람들은 과연 API 통신 코드라고 생각할까 전역 상태 관리라고 생각할까?

이러한 점을 해결하기 위해 탄생한 것이 리액트 쿼리이고, 리액트 쿼리는 전역 상태 관리 라이브러리가 아닌 서버 상태 관리 라이브러리라고 하면 맞겠다.

설치

현재 최신 버전은 v5 이다.

react-query v3

$ npm i react-query
# or
$ yarn add react-query

react-query v5

$ npm i @tanstack/react-query
# or
$ pnpm add @tanstack/react-query
# or
$ yarn add @tanstack/react-query

기본 사용법

react-query v3 기준으로 작성되었다.

Provider

리액트 쿼리를 사용하기 위해서는 앱의 최상단에서 Provider를 이용해 queryClient를 제공해줘야 한다.

import {QueryClient, QueryClientProvider} from 'react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AppRouter />
    </QueryClientProvider>
  );
}

Queries

쿼리는 데이터를 가져오기 위해 사용한다. 각 쿼리마다 unique한 key를 부여해야 하며 여기서 쿼리는 data fetching 함수를 말한다.
useQuery Hook을 이용하여 지정할 수 있다. isLoading, isError, isSuccess, isIdle의 쿼리 결과 status를 나타내는 state를 반환하며, error, data, isFetching 과 같은 결과 정보또한 state로 반환한다.

const { isLoading, isError, data, error } = useQuery('todos', fetchTodoList)

export const fetchTodoList = async () => {
  const {data} = await todoAPI.get('/todos');
  return data;
};

Mutations

mutations은 Create, Delete, Update를 할 때 사용한다. useMutation Hook을 이용한다.
isIdle, isLoading, isError, isSuccess, error, data등의 state를 반환한다.

const mutation = useMutation(newTodo => {
  return axios.post('/todos', newTodo)
})

mutations에서는 onSuccess 옵션과 함께 invalidateQueries 메서드를 이용하면 invalidateQueries에 들어간 query를 다시 실행한다.

const mutation = useMutation(newTodo, {
  onSuccess: () => {
    queryClient.invalidateQueries('todos');
  },
});

Query Invalidation

invalidateQueries가 적용되면 다음과 같은 일들이 일어난다.

  1. 해당 쿼리가 '오래된 것'으로 표시된다.
  2. 해당 쿼리가 useQuery를 통해 렌더링 되고 있다면, 백에서 다시 불러와진다.

리액트 쿼리를 이용해 API호출을 더 효율적이고, 쉽게 이용할 수 있게 됐다. 위에서 나열한 기본 방법들 말고, 더 잘 이용할 수 있게 공부해야겠다.

profile
프론트엔드 개발자

0개의 댓글