React Toolkit

Table of contents

configureStore

기본적으로 redux-thunk를 포함하고, redux devtools extension을 사용할 수 있다.

import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { rootReducer } from "./reducers";

const composeEnhancers =
  (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export const store = createStore(
  rootReducer,
  composeEnhancers(applyMiddleware(thunk))
);


// redux-toolkit의 configureStore 적용
import { configureStore } from "@reduxjs/toolkit";
import { rootReducer } from "./reducers";

export const store = configureStore({
  reducer: rootReducer
});

기본적으로 포함된 미들웨어는 redux-thunk, immutability, serializability가 있다.

// thunk 미들웨어만 사용하는 경우
const store = configureStore({
  reducer: rootReducer
  middleware: [thunk]
});

createAction

action 타입 선언과 action 생성자 함수를 포함한 것이다.

const ADD_TODO = "ADD_TODO"

const addTodo = (todo) => ({
  type: ADD_TODO
  todo
})

console.log(addTodo('작성하기'))
// return {type: 'ADD_TODO', todo: '작성하기'}


// createAction 사용
const addTodo = createAction('ADD_TODO')

console.log(addTodo('작성하기'))
// return {type: 'ADD_TODO', payload: '작성하기'}

createReducer

immer가 내부적으로 사용된다.

const INCREMENT = "INCREMENT"
// immer produce 사용 시 reducer
const counter = produce((draft, action) => {
  switch (action.type) {
    case INCREMENT:
      draft.value++
    }
  },
  { value: 0 }
);


// createReducer 사용
const increment = createAction('INCREMENT')

const counter = createReducer({ value: 0 }, (builder) => {
  builder
    .addCase(increment, (state, action) => {
      state.value++
    })
})

builder methods는 addCase, addMatcher, addDefaultCase가 있다.

createSlice

내부적으로 createAcion과 createReducer를 사용한다.

Parameters
name: action type의 접두사로 사용된다.
initialState: 초기 state
reducers: reducer를 정의하되 해당 key 이름으로 createAction이 된다.

const counter = createSlice({
  name: 'counter'.
  initialState: { value: 0 },
  reducers: {
    increment: (state, action) => {
      state.value++
    }
  }
})

// action 생성자 increment
const { increment } = counter.actions

// reducer
const rootReducer = combineReducers({
  counter: counter.reducer
})

extraReducers: 정의된 action type이 아닌 action type에 의해 실행 시킬 수 있다.
(기본예시) createAsyncThunk와 사용 시 promise의 상태에 따라 reducer 실행 가능

createAsyncThunk

return 값은 promise 상태 생명주기 중 fulfilled에 응답한다. rejected에 반응하기 위해서는 rejectWithValue를 통해 값을 반환하면 된다.

Parameters
type: action type으로 promise 상태 생명주기가 붙는다.
(기본예시) type이 “example/request” 일 경우 “example/request/pending” 이 후에 연산 결과에 따라 “example/request/fulfilled” 또는 “example/request/rejected” action type이 보내진다.

const example = createAsyncThunk("example/request", async (arg, thunkAPI) => {
    try {
      const res = await fetch( ... )
    
      return "fulfilled"
    } catch {
      return thunkAPI.rejectWithValue("rejected")
    }
  }
)

const counter = createSlice({
  name: "counter",
  initialState: { value: 0 },
  reducers: {},
  extraReducers: {
    [example.fulfilled]: (state, action) =>{
      console.log(action.payload) // returns "fulfilled"
    },
    [example.rejected]: (state, action) => {
      console.log(action.payload) // returns "rejected"
    }
  }
})

참조
https://redux-toolkit.js.org/
https://github.com/reduxjs/redux-toolkit