[React] createSlice(), configureStore(), createApi()

최예린·2022년 10월 25일
0

React

목록 보기
17/19

redux toolkit에 대한 강의는 여러개 찾아서 듣고 있지만
아직까지는 개념 숙지가 덜된 것 같아서 따로 개념을 정리하고자 합니다.


Reducer 만들기 - createSlice()

redux 코드

let initialState = {
  productList: [],
  selectedItem: null,
};

function productReducer(state = initialState, action) {
  let { type, payload } = action;
  switch (type) {
    case "GET_PRODUCT_SUCCESS":
      return { ...state, productList: payload.data };
    case "GET_SINGLE_PRODUCT_SUCCESS":
      return { ...state, selectedItem: payload.data };
    default:
      return { ...state};
  }
}

export default productReducer;

redux toolkit 코드

import { createSlice } from '@reduxjs/tookit";

let initialState = {
  productList: [],
  selectedItem: null,
};

const productSlice = createSlice({
  name: "product",
  initialState,
  reducers: {
    getAllProducts(state, action) {
      state.productList = action.payload.data;
    },
    getSingleProduct(state, action) {
      state.selectedItem = action.payload.data;
    },
  },   
});

export default productSlice.reducer;

1. 기본 문법

createSlice()는 Reducer를 만드는 걸 도와줍니다.
인자로 객체를 받는데 그 객체는 name/initialState/reducers를 필수적으로 포함해야합니다.

  • name
    reducer를 설명하는 이름을 붙여줍니다.
  • initialState
    이전에 redux를 사용할 때와 동일합니다. 초기상태를 의미하며 reducer에 state로 전달됩니다.
  • reducers
    reducer들을 정의합니다. 기존과 다른 것은 if문이나 switch 문으로 작성하던 것에서 여러개의 함수를 작성하는 것으로 바뀌었습니다. 함수는 state와 action을 인자로 받습니다.

2. 변경점

  • createAction ❌, createReducer ❌
    createAction, createReducer 함수가 내부적으로 사용되며 createSlice에 선언된 슬라이스 이름을 따라서 리듀서와 그리고 그것에 상응하는 액션 생성자와 액션 타입을 자동으로 생성합니다. 따라서 createSlice를 사용하면 따로 createAction, createReducer를 작성할 필요가 없습니다.

  • reducer { ...state, } ❌
    기존코드에서는 switch문에서 항상 return을 필수적으로 해야했고, 원래있던 state값은 유지하되 거기에서 원하는 부분만 바꿀때는 { ...state, } 이 문법을 작성해야했습니다. 지금은 return할 필요도 없어졌고 계속 반복해서 ...state를 작성할 필요가 없어졌습니다.

  • export
    reducers에 만든 모든 함수들이 자동으로 reducer로 묶어지기때문에
    export 할 때 XXX.reducer
    마지막에는 결국 하나의 큰 리듀서이기때문에 s를 붙이지않습니다.


Store 만들기 - configureStore()

createStore() 코드

import { createStore, applyMiddleWare } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
         
let store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleWare(thunk))
);

export default store;
  • combineReducer: reducer들을 하나로 묶은 것
  • thunk
  • applyMiddleware: thunk를 위한 미들웨어
  • composeWithDevTools

이 네가지를 기본으로 항상 써야했습니다.

configureStore() 코드

import { configureStore } from "@reduxjs/toolkit";

let store = configureStore({
  reducer: {
    auth: authenticateReducer,
    product: productReducer,
  },
});

export default store;
  • redux가 버전 업그레이드되면서 기존에 사용했던 createStore()대신 configureStore()를 사용하도록 권장하고있습니다.

  • configureStore()는 위에서 언급한 4가지를 모두 자동으로 커버해주기때문에 사용할 필요가 없습니다.

  • configureStore에 전달하는 객체 내부에
    reducer:에 객체{} 를 통해 필요한 reducer를 바로 넣으면 됩니다.

Action dispatch - Action 호출하기

위에서 reducer를 만들 때
switch문과 "GET_PRODUCT_SUCCESS"를 사용하지않고
getAllProducts(state, action) 이런식으로 함수를 정의했습니다.
그러면 Action을 호출할 때 type에 뭘 입력할지?? 에 대한 의문이 생깁니다.

createStore()일때 Action 호출

function getProducts(searchQuery) {
  return async (dispatch, getState) => {
    let url = ``'
    let response = await fetch(url);
    let data = await response.json();
    dispatch({type: "GET_PRODUCT_SUCCESS", payload: {data}});
  };
}

configureStore()일때 Action 호출

export const productActions = productSlice.actions;

createSlice가 만든 유니크한 액션값들을 사용합니다.
그렇게 하기위해서는 액션도 export를 해야합니다.

import { productActions } from "../reducers/productReducer";

function getProducts(searchQuery) {
  return async (dispatch, getState) => {
    let url = ``'
    let response = await fetch(url);
    let data = await response.json();
    dispatch(productActions.getAllProducts({ data }));
  };
}

매개변수로 전달된 값은 이름을 굳이 payload라고 쓰지않아도 알아서 payload라는 필드 아래로 들어가게됩니다.
예시) action.payload.data


API 만들기 - createApi()

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

export const apiSlice = createApi({
    reducerPath: 'api',
    baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:3500' }),
    tagTypes: ['Todos'],
    endpoints: (builder) => ({
        getTodos: builder.query({
            query: () => '/todos',
            transformResponse: res => res.sort((a, b) => b.id - a.id),
            providesTags: ['Todos']
        }),
        addTodo: builder.mutation({
            query: (todo) => ({
                url: '/todos',
                method: 'POST',
                body: todo
            }),
            invalidatesTags: ['Todos']
        }),
        updateTodo: builder.mutation({
            query: (todo) => ({
                url: `/todos/${todo.id}`,
                method: 'PATCH',
                body: todo
            }),
            invalidatesTags: ['Todos']
        }),
        deleteTodo: builder.mutation({
            query: ({ id }) => ({
                url: `/todos/${id}`,
                method: 'DELETE',
                body: id
            }),
            invalidatesTags: ['Todos']
        }),
    })
})

export const {
    useGetTodosQuery,
    useAddTodoMutation,
    useUpdateTodoMutation,
    useDeleteTodoMutation
} = apiSlice

endpoints

서버에 대해 수행하려는 작업 집합입니다. 빌더 구문을 사용하여 객체로 정의합니다. 두 가지 기본 끝점 유형이 있습니다. query및 mutation.

tagTypes

문자열 태그 유형 이름의 배열입니다. 태그 유형 지정은 선택 사항이지만 캐싱 및 무효화에 사용할 수 있도록 정의해야 합니다. 태그 유형을 정의할 때 엔드포인트 를 구성할 때 태그 유형 을 제공 하고 무효화 할 수 있습니다 .providesTags, invalidatesTags

reducerPath

reducerPath서비스 가 스토어에 탑재될 고유 키 입니다. 애플리케이션에서 두 번 이상 호출하는 경우 createApi매번 고유한 값을 제공해야 합니다. 기본값은 'api'입니다.

providesTags

(optional, only for query endpoints)

Used by query endpoints. Determines which 'tag' is attached to the cached data returned by the query. Expects an array of tag type strings, an array of objects of tag types with ids, or a function that returns such an array.

invalidatesTags

(optional, only for mutation endpoints)

Used by mutation endpoints. Determines which cached data should be either re-fetched or removed from the cache. Expects the same shapes as providesTags.

profile
경북대학교 글로벌소프트웨어융합전공/미디어아트연계전공

0개의 댓글