Purpose

Redux toolkit은 Redux logic 작성의 표준이 되기 위해 탄생했습니다. 리덕스 툴킷은 아래와 같은 리덕스의 3가지 문제점을 해결해줍니다.

  • Redux store 설정이 너무 복잡하다.
  • 유용한 기능 구현을 위해 여러가지 패키지가 추가적으로 필요하다
  • 리덕스를 위한 boilerplate가 너무 많다.

Redux toolkit은 create-react-app처럼 세팅 과정과 보편적 use cases에 대한 추상화를 제공하는 기능을 지원합니다. 또한 사용자가 어플리케이션 코드를 간편화하기 위한 유용한 툴도 제공합니다.

또한 RTK Query라고 하는 분리된 데이터 패칭 툴을 제공합니다. 이와 관련된 내용은 다음 포스팅에서 다뤄보겠습니다.

Redux toolkit은 모든 리덕스 사용자들에게 더 나은 코드베이스를 제공하기 위해 탄생한 도구입니다.

Installation

Using Create React App

일반적으로 가장 추천되는 방법입니다.

# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript

An Existing App

#NPM
npm install @reduxjs/toolkit

#Yarn
yarn add @reduxjs/toolkit

window.RTK 글로벌 변수를 제공하는 UMD 패키지로도 사용이 가능합니다. UMD 패키지는 script태그를 이용해 바로 이용할 수 있습니다.

What's Included

Redux toolkit은 다음과 같은 API를 포함하고 있습니다.

  • configureStore(): createStore를 wrapping 하여 간단한 설정 세팅과 좋은 기본 설정을 제공합니다. 자동으로 slice reducers를 합쳐주며 사용자에게 제공받는 리덕스 미들웨어를 더해줍니다. redux-thunk를 기본으로 제공하며 Redux DevTools Extension을 사용할 수 있게 해줍니다.
  • createReducer(): switch 문을 작성하는 대신 case reducer 함수에 작업 유형의 lookup table을 제공합니다. 또, 자동으로 immer library를 사용하여 immutable updates를 일반적인 코드로 구현할 수 있도록 도와줍니다.
  • createAction(): action type string을 제공하는 action 생성자 함수를 생성합니다. 함수 자체에 toString()이 정의되어 있어 상수 대신 사용할 수 있습니다.
  • createSlice(): reducer functions 객체와 slice name, initial state value를 받아 자동으로 slice reducer와 그에 대응하는 action creators, action types를 생성합니다.
  • createAsyncThunk: action stype string과 promise를 리턴하는 함수를 받아 thunk를 생성합니다. 생성된 thunk는 promise를 기반으로pending/fulfilled/rejected action types를 dispatch 합니다.
  • createEntityAdapter: 재사용 가능한 reducer, selector 세트를 생성하여 store의 data normalize를 관리할 수 있도록 도와줍니다.
  • Reselect library의 쉬운 사용을 위해 createSelector utility를 제공합니다.

Create a Redux Store

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: {},
})

위 코드는 Redux store를 생성하고, 자동으로 Redux DevTools extension을 설정해줍니다.

Provide the Redux Store to React

스토어가 생성되면 React-Redux의 Provider 세팅을 통해 React components에서 사용 가능하도록 설정할 수 있습니다.

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { store } from './app/store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Create a Redux State Slice

slice생성은 string name, initial state value, state 업데이트에 대한 one or more reducer functions가 필요합니다. Redux toolkit의 createSlice와 createReducer API는 내부적으로 Immer를 사용하여 일반적 'mutating' update logic이 correct immutable updates가 되도록 도와줍니다.

// features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  value: 0,
}

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload 
    },
  }
})

// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer

Add Slice Reducers to the Store

이제 reducer 함수를 counter slice로 부터 import하여 우리의 store에 추가해야 합니다. reducer parameter안의 field를 정의함으로써 상태 변화시 store에 slice reducer function을 사용하도록 할 수 있습니다.

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
})

Use Redux State and Actions in React Components

이제 React-Redux hooks를 통해 리액트 컴포넌트에서 redux store와 상호작용 하도록 사용할 수 있습니다. store로 부터 data를 읽기 위해 useSelector를, action dispatch를 위해 useDispatch를 사용할 수 있습니다. Counter 컴포넌트를 만들고 이를 App에서 렌더링 하도록 개발합니다.

// features/counter/Counter.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'

export function Counter() {
  const count = useSelector((state) => state.counter.value)
  const dispatch = useDispatch()
  
  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          Increment
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          Decrement
        </button>
      </div>
    </div>  
  )
}

이제 Increment, Decrement 버튼을 클릭하면 다음과 같은 일이 일어납니다.

  • The corresponding Redux action will be dispatched to the store
  • The counter slice reducer will see the actions and update its state
  • the Counter component will see the new state value from the store and re-render itself with the new data

Summary

  • Create a Redux store with configureStore
    • configureStore accepts a reducer function as a named argument
    • configureStore automatically sets up the store with good default settings
  • Provide the Redux store to the React application components
    • Put a React-Redux Provider component around your App
    • Pass the Redux store as Provider's 'store' props
  • Create a Redux "slice" reducer with createSlice
    • Call createSlice with a string name, an initial state, and named reducer functions
    • Reducer functions may "mutate" the state using Immer
    • Export the generated slice reducer and action creators
  • Use the React-Redux useSelector/useDispatch hooks in React components
    • Read data from the store with the useSelector hook
    • Get the dispatch function with the useDispatch hook, and dispatch actions as needed

What's Next?

리덕스 툴킷은 리덕스를 Wrapping하여 쉽게 사용할 수 있도록 도와주는 도구입니다. 따라서 Redux EssentialsRedux Fundamentals tutorial을 읽어본다면 Redux가 어떻게 동작하는지, Redux toolkit이 어떤 역할을 해주는지, 어떻게 완벽하게 사용할 수 있는지 알 수 있을 것입니다.

출처

profile
웹 개발을 공부하고 있는 윤석주입니다.

0개의 댓글