본문 바로가기

React/Redux

[React] Redux-toolkit : createSlice, createAsyncThunk, configureStore

원래 하던대로 Redux 상태관리 코드를 짜다가 '아 왜이렇게 폴더가 많아!!!!' '왜이렇게 코드길이가 길어!!!!!' 궁시렁대면서 어찌저찌 store 부터 dispatch까지 구현했는데 데이터를 받아오는 거 처음부터 화면도 안떠서 화가 났었던 오늘..

 

그리고 진짜 너무 오랜만에 React 프로젝트를 만들다 보니 Redux를 사용하는데 있어서 부가적으로 필요한 라이브러리들도 골치 아프고

요건 또 뭐야..

열심히 iOS공부하는 동안.. createStore는 지원도 안하고..

 

저걸 어떻게 바꾸지? 하면서 구글링 하던 중,, redux-toolkit에 대해 알게 되는데..!

 

서론이 길었지만,,

코드도 짧게 할 수 있고 라이브러리도 덜 사용하는 이 redux-toolkit에 대해 포스팅을 시작해보겠당

 

 

 

 


 

 

Redux-Toolkit

- 리덕스에서 공식적으로 내놓은 패키지로, 리덕스를 사용하는데 있어 적극 권장되고 있다!

- 뭐가 좋은지는 계속 알아보자.

 

 

 

일단, 툴킷 라이브러리 적용

yarn add @reduxjs/toolkit

 

 

 

1️⃣ createSlice()

- reducer 만드는 것을 도와줌

const postSlice = createSlice({
    name: 'post',
    initialState,
    reducers: {
        getAllPosts(state, action) {
            state.postList = action.payload.data
        }
    },
})

name: slice에 대한 이름, action 이름을 만드는 데 name이라는 키가 쓰임 (prefix로 사용)

 initialState: reducer에서 사용될 초기 state 값

 reducers: 사용될 모든 functions를 만들어줌

각각의 functions는 state, action 매개변수를 가짐

여기서 state 매개변수는 initialState와 같다고 생각하자.

요 functions를 작성할 때, createSlice는 …state 이런 불변성 유지를 위한 코드나 반환(return)키워드를 쓰지 않아도 된다. 아주 편리함!

state.postList = action.payload.data 처럼 그냥 내가 바꾸고 싶은 값만 써주면 됨

 

 

 

마지막으로, 위에서 만든 reducer를 export 해줘야함 → createSlice를 받는 변수의 reducer

createSlice변수.reducer : 왜 reducers가 아닌가? 결국 reducers를 모은 하나의 큰 reducer이기 때문이다.

 

그리고 나중에 dispatch 작업을 위한 action을 export 해줘야함 (dispatch에 대한 것은 뒤에서 자세히 다룰 것)

createSlice변수.actions

 

 

 

 

 

 

 

 

2️⃣ createAsyncThunk

- 비동기 작업을 처리하는 액션을 만들어준다

- createAsyncThunk(액션 타입, 액션 creator가 실행되었을때 처리될 작업)

 

이걸로 만들어진 작업의 3가지 메소드(상태)

  • pending : 비동기 작업을 시작했을 때
  • fulfilled : 비동기 작업이 끝났을 때
  • rejected : 오류가 생김

 

비동기 작업은 action creators를 자동으로 만들지 못한다.

createSlice의 extraReducers안에서 정리한다!

 

 

extraReducer?

- 자신이 구현한 외부 비동기 작업 함수 사용시 사용되며, 외부에서 만들어진 action을 처리하기 때문에 외부에서 만들어진 함수를 property이름으로 사용하고, 자동으로 pending, fulfilled, rejected의 type을 가지 action을 구현해줌

 

- 그래서 pending fulfilled, rejected 에 맞게 extraReducers를 작성하면 됨

 

const postSlice = createSlice({
    name: 'post',
    initialState,
    reducers: {},
    extraReducers: {
    [getPostsThunk.pending]: (state, action) => ({
        ...state,
        loading: true,
      }),
      [getPostsThunk.fulfilled]: (state, action) => ({
        ...state,
        loading: false,
        postList: action.payload,
      }),
      [getPostsThunk.rejected]: (state, action) => ({
        ...state,
        loading: false,
        error: action.payload,
      }),
    }
})

 

 

 

 

 

 

 

3️⃣ configureStore()

앞에 서론에서 언급 한번 했었는데,, 리덕스가 버전이 업그레이드 되면서 더이상 createStore를 지원하지 않음!!!!

 

기존 createStore

  • 여러개의 reducers를 combineReducers를 사용해 묶어 createStore의 rootReducer에 내보냈었음
  • thunk를 썼어야했고, thunk를 위한 applyMiddleWare를 써줬어야 했다.
  • redux dev-tool인 composeWithDevTools를 사용했어야 했다.

confitureStore에서는?

  • 여러개의 reducers를 combineReducers를 사용해 묶어 createStore의 rootReducer에 내보냈었음 → 자동 set-up!
  • thunk를 썼어야했고, thunk를 위한 applyMiddleWare를 써줬어야 했다. → 자동 set-up!
  • redux dev-tool인 composeWithDevTools를 사용했어야 했다. → 자동 set-up!

 

combineReducer에서 합쳐줬던 reducers들을 그냥 바로 써주기만 하고 store을 export해주면 끝!

import { configureStore } from '@reduxjs/toolkit'
import postReducer from './reducers/postReducer'

const store = configureStore({
    reducer: {
        post: postReducer
    }
})

export default store

 

 

진짜 왕 간단..

 

 

 

 

 

 

4️⃣ Dispatch

근데, createSlice에서 reducers를 정리할 때, type은 없었는데 ?! 그러면 어떻게 dispatch 작업을 할까? 

→ createSlice가 만든 유니크한 actions들을 가지고 올 것이다.

 

dispatch({type:payload:})   dispatch({받아온actions이름.받아온reducer이름(전달할data)})

  • reducer의 매개변수로 전달된 값은 자동으로 payload의 필드 아래로 들어감
    → payload: 이라고 쓸 필요 없이 그냥 바로 data를 매개변수로 전달해주면 됨

 

 

 

 

 

 


예전에 리덕스 처음 공부할 때 너무 복잡하고 그래서 제일 뭔가 공부하기 힘들었던 기억이 나는데.. 개발하면서도 폴더 구성하기 머리아프고.. 라이브러리들도 왕많고...

근데 redux-toolkit 보니까 진짜 너무 간단한데.. 왜 이제야 나온거야?!

 

이거 나중에 GDSC 세션 진행할 때 나 처럼 고생하지 말라고.. 

꼭.. 알려드려야지...