Redux toolkit & Thunk

uub_2·2022년 8월 14일
0

Redux

목록 보기
2/2

Redux toolkit

Redux와 Redux toolkit 코드 비교

1. Redux

  • action type, action creator 따로 선언
  • name, initialState, reducers(s 빼먹지마)를 필수로 포함
// action type
const ADD_DATA = 'dataChange/add'
const DELETE_DATA = 'dataDelete/delete'

// action creator
// 액션객체를 타입으로, 준비물은 payload로 가지고 행위를 할 것이다 정의, 화살표 함수
export const addData = (payload) => {
    return {type: ADD_DATA, payload: payload}
}

export const deleteData = (payload) => {
    return {type: DELETE_DATA, payload: payload}
}

// reducer
export default function DataReducer (state=[], action) {
    // state에 초기값 설정 state=[]
    switch (action.type) {
        // 액션 타입을 case와 비교하면서 맞는 case로 실행
        case ADD_DATA:
            console.log(state, action, [...state, action.payload])
            return [...state, action.payload]

        case DELETE_DATA:
            return [...state].filter(object => object.title !== action.payload)
            //object가 object.title을 가지고 있는지 확인
        default:
            return state
    }
}

configStore 비교

rootReducer를 사용해서 리듀서의 묶음 생성

import { createStore } from "redux";
import { combineReducers } from "redux";
import counter from "../modules/counter";

const rootReducer = combineReducers({
  counter,
});
const store = createStore(rootReducer);
export default store;

2. Redux toolkit

  • slice 사용 -> createSlice api를 통해 slice 작성
  • name, initialState, reducers 필수로 들어가야함
  • action type 따로 선언할 필요 없음
import { createSlice } from "@reduxjs/toolkit";

const ToolkitSlice = createSlice({
    name: "dataChange",
    initialState: [],
    reducers: {
        ADD_DATA: (state, action) => {
            console.log(state, action, [...state, action.payload])
            return [...state, action.payload]
        },
        DELETE_DATA: (state, action) => {
            return [...state].filter((object => object.title !== action.payload))
        }
    }
})

slice, createSlice

createReducer

(위 예시 코드에는 없음)

  • 복사해서 새로운 state를 만들어 return 해줄 필요 없이(구조 분해 할당으로 기존 state 할당해줄 필요 없이) push()로 state의 변경되는 요소만 변경 시킬 수 있음 (push는 어떤 것도 return 하지 않음)
    물론, 새로운 state Object를 return 시켜도 상관 없음
  • switch 구문 필요 없음
  • 예시 코드
import {createReducer} from '@reduxjs/toolkit'

const initialState = {
    loading: false,
    data: [],
    error: null,
};
const reducer = createReducer(initialState, {
  // push() 방식
    [getUsersStart]: (state) => {
        state.push({ loading: true });
    },
  // return 방식
    [getUsersSuccess]: (state, action) => ({...state, loading: false, data: action.payload });
    ,
    [getUsersFail]: (state, action) => {
        state.push({ loading: false, error: action.payload });
    },
});

export default reducer;

configStore 비교

  • configStore api 사용, 슬라이스 파일 import
import { configureStore } from '@reduxjs/toolkit';
import ToolkitSlice from './modules/module';

export const store = configureStore({
  reducer: {
    data: ToolkitSlice.reducer,
  },
});

export default store;

extra reducer

  • 외부에서 받아오는 비동기 작업을 하는 함수에서 사용됨
  • 외부 함수 이름을 property 이름으로 작성
  • pending, fulfilled, rejected 의 타입을 가진 액션을 구현, 이 타입에 맞게 함수 작성
    자세한 내용은 thunk에서

Redux 미들웨어 - Thunk

미들웨어란 액션과 리듀서 사이의 중간자이다.

thunk는 리덕스를 사용하는 애플리케이션에서 비동기 작업을 처리하는 용도로 사용하며, 특정 작업을 나중에 하도록 미루기 위해 함수형태로 감싼 것을 이야기한다.

thunk

thunk를 사용하면 dispatch를 할 때 객체가 아닌 함수를 dispatch 할 수 있게 한다.
이 함수를 thunk 함수라고 한다.

dispatch(함수) → 함수실행 → 함수안에서 dispatch(객체)

thunk 함수 만들기

  • 컴포넌트
  useEffect(() => {
    dispatch(getPostAysnc());
  }, []);

  const postData = useSelector((state) => state.Post.data);

getPostAysnc()를 디스패치 했고, useSelctor를 이용해서 state값을 요청했다.


createAsyncThunk api를 사용해서 thunk 함수를 생성한다.

export const getPostAysnc = createAsyncThunk(
	// createAsyncThunk는 비동기 작업을 처리하는 액션을 만들어 준다.
  "post/getPost",
  //"액션밸류/액션크리에이터"
  async (thunkAPI) => {
    try {
      const res = await axios.get(get 요청할 api주소);
      return res.data;
    } catch (error) {
      return thunkAPI.rejectWithValue(error);
    }
  }
);
  • async, await
  • try, catch

Reducers 작성

export const PostSlice = createSlice({
  name: "postReducer",
  initialState: [],
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getPostAysnc.fulfilled, (state, action) => ({
        ...state,
        data: action.payload,
      }))
      .addCase(pickPostAysnc.fulfilled, (state, action) => {
        state.data = action.payload;
      });
  },
});
  • thunk를 사용할 때는 extraReducers 를 사용

reducer, extraReducer

동기적인 액션은 reducer, 비동기적 액션은 extraReducer

대략적인 흐름

컴포넌트에서 useSelector로 스토어에 정보 요청 ->
reducers 실행 ->
extraReducer 에서 reducers 작업 상태에 따라 pending, fulfilled, rejected로 구분해서 builder.addCase() 내용 실행 ->
이 값이 state로 전달

profile
우웁이

0개의 댓글