RTK QUERY

Inseok Park·2022년 9월 13일
3
post-thumbnail

RTK Query 란?

redux toolkit 에는 createAsyncThunk 를 사용해서,
thunk 를 만들어서 async 요청을 관리할 수 있도록 하는 기능이 있다.
그런데 createAsyncThunk 의 경우 async 요청의 응답을 따로 createSlice 를 활용해서 관리해줘야 해서, 코드가 늘어날 수 밖에 없다.

RTK Query는 Redux Toolkit 의 createSlicecreateAsyncThunk 의 기능을 동시에 사용하면서,
react-query 와 유사하게 백엔드에서 넘어온 데이터를 관리할 수 있는 기능이 만들어져있다.
또한 캐싱 관련 기능도 지원하기 때문에, 불필요한 요청을 줄일 수도 있다.
그리고 post 하자마자 자동으로 get 하는 기능까지도 구현할 수 있다.
뿐만 아니라, 프론트 데이터와 api 데이터 관리하는 로직 자체를 분리시킬 수도 있습니다.

백엔드와의 요청을 통해서 받아오는 데이터 → RTK Query 로 관리

프론트엔드만의 데이터 → createSlice 로 관리

Setting

terminal
yarn create react-app 프로젝트명
yarn add @reduxjs/toolkit react-redux

최상단에 .env파일 만들어서 백엔드 주소 관리
REACT_APP_API_URL=https://jsonplaceholder.typicode.com
이렇게 작성하면 추후에 baseUrlprocess.env.REACT_APP_API_URL 라고 작성할 수 있다.

기본형식

(src/api/postApi.js)

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
 
export const api이름 = createApi({
  reducerPath: '리듀서이름',
  baseQuery: fetchBaseQuery({
    baseUrl: process.env.REACT_APP_API_URL,
  }),
  endpoints: (builder) => ({
    요청이름: builder.query({
      query: (주소에 넘길 값) => 'api 주소값/(주소에 넘길 값)',
    }),
  }),
});
 
export const {
  use요청이름Query
} = postApi;

endpoints 에 보내고자 하는 요청 이름을 명시하면,
자동으로 use요청이름Query 를 사용할 수 있게 된다.

요청을 명시할 때 builder.query 라고 작성하게 되면, get 요청을 보낼 수 있게 되고,
builder.mutation 이라고 작성하면, post 혹은 put 요청 등을 보낼 수 있게 된다.

예를들어 아래 주소에 get요청을 보내는 endpoints를 작성하려면 아래처럼 작성하면 된다.
https://jsonplaceholder.typicode.com/posts

getPosts: builder.query({
      query: () => 'posts',
    }),

(src/api/postApi.js)

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
 
export const postApi = createApi({
  reducerPath: 'postApi',
  baseQuery: fetchBaseQuery({
    baseUrl: process.env.REACT_APP_API_URL,
  }),
  endpoints: (builder) => ({
    getPosts: builder.query({
      query: () => 'posts',
    }),
  }),
});
 
export const {
  useGetPostsQuery
} = postApi;

api작성을 완료하면 store를 만들어준다.

(src/store/index.js)

import { configureStore } from '@reduxjs/toolkit';
import { postApi } from '../api/postApi';
import { setupListeners } from '@reduxjs/toolkit/query';
 
export const store = configureStore({
  reducer: {
    [postApi.reducerPath]: postApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(postApi.middleware),
});

setupListeners(store.dispatch);

위에서 setupListeners 는 서비스 내에서 사용자의 행동이나 요소의 변화 등을 지켜보다가,
요청을 보낼 수 있도록 listener 를 준비해놓기 위한 함수로
액션을 실행할 때인 store.dispatch로 설정했다.

스토어 작성이 완료되었으면 컴포넌트를 작성해준다.

(src/components/Post.jsx)

import React from 'react';
import { useGetPostsQuery } from '../api/postApi';
 
function Posts() => {
  const { data: posts, isLoading, isError } = useGetPostsQuery();
// 위처럼 사용하면, 동작을 수행하면서 자동으로 isLoading, isError, data 를 반환해준다.
// 직접 isError 등을 정의해줄 필요없이 바로 받아와서 사용해줄 수 있다.
  if (isLoading) {
    return <div>로딩 중...</div>
  }
  if (isError || !posts) {
    return <div>오류 발생</div>;
  }
  return (
    <div>
        {posts.map((post) => (
            <>
            <p>{post.title}</p>
            <p>{post.body}</p>
            </>
        ))}
    </div>
  );
};
 
export default Posts;

마지막으로 app.js는 기존처럼 provider로 래핑해준다.

(app.js)

import { Provider } from 'react-redux';
import Posts from './components/Posts';
import {store} from './store/index';

function App() {
  return (
    <Provider store={store}>
      <Posts/>
    </Provider>
  );
}

export default App;

Tag 활용

(postApi.js)

import {createApi, fetchBaseQuery} from '@reduxjs/toolkit/query/react'

export const postApi = createApi({
  reducerPath: 'postApi',
  tagTypes: ['Posts'],
  baseQuery: fetchBaseQuery({
    baseUrl: process.env.REACT_APP_API_URL,
  }),
  endpoints: (builder) => ({
    getPosts: builder.query({
      query: () => 'posts',
      providesTags: [{ type: 'Posts', id: 'LIST'}]
    }),
    getPostById: builder.query({
      query: (postId) => `posts/${postId}`,
      providesTags: (result, error, postId) => [{type: 'Posts', id: postId}]
    }),
    createPost: builder.mutation({
      query: ({data}) => ({
        url: 'posts',
        method: 'POST',
        body: data,
      }),
      invalidatesTags: (result) => result ? [{type: 'Posts', id: 'LIST'}] : []
    })
  })
})

export const { useGetPostsQuery, useGetPostByIdQuery, useCreatePostMutation } = postApi

위에서 Tag는 각 요청마다의 cache 이름을 뜻한다.
invalidatesTags는 기존에 요청보냈던 결과 cache를 없애고 해당 Tag에 대한 요청을 다시 보내는 것을 말한다.
그래서 위 createPost 메서드의 경우 post요청 이후에 자동으로 get요청이 가는 것을
개발자모드 네트워크탭에서 확인할 수 있다.

이처럼 RTK Query는 백엔드 Api 데이터를 관리하는 로직을 프론트엔드 데이터와 분리시킬 수 있을 뿐만 아니라 가독성이 좋고, 캐싱관련 기능도 지원하기 때문에 좋은 활용 방법인 것 같다.

0개의 댓글