[react] Redux Toolkit 튜토리얼

sue·2021년 4월 27일
1

react note

목록 보기
14/17

redux-toolkit 공식 문서 튜토리얼 내용을 개인 학습용으로 정리한 글입니다.

Redux Toolkit

사용 목적

Redux Toolkit은 Redux를 사용하기 쉽게 만들기 위해 Redux 팀에서 공식으로 제공하는 개발도구 입니다. Redux Toolkit은 Redux에 대한 세 가지 일반적인 문제를 해결하기 위해 만들어졌습니다.

Redux의 문제점

  • Store 구성이 복잡하다
  • 유용한 일을 하도록 하려면 많은 패키지에 의존해야 한다
  • 너무 많은 보일러플레이트 코드가 필요하다
    * boilerplate: 최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드

모든 사례를 해결할 수는 없지만 create-react-appapollo-boost의 정신에 따라, Redux Toolkit은 설정 프로세스를 추상화하고, 가장 일반적인 사용 사례를 처리하는 몇 가지 도구를 제공하고, 사용자가 어플리케이션 코드를 단순화 할 수있는 몇 가지 유용한 유틸리티를 포함하고 있습니다.

리덕스는 기본적으로 액션 타입, 액션 생성함수, 리듀서를 정의하는 코드를 작성해야 하기 때문에 보일러플레이트 코드를 많이 준비할 수밖에 없다. 이 과정에서 코드 단순화를 위해 redux-actions을, typescript 지원을 위해 typesafe-actions, 불변성 간소화 코드 작성을 위해 immer 등등의 라이브러리를 별도로 도입해야 했다. 리덕스 툴킷은 이런 문제를 해결하기 위해 리덕스 개발팀에서 공식적으로 제공하는 라이브러리이다. 기본적으로 리듀서, 액션타입, 액션 생성함수, 초기상태를 하나의 함수로 선언할 수 있다. 이 4가지를 통틀어서 slice 라고 정의한다.

Redux Toolkit 특징

  1. Simple
    스토어 설정, 리듀서 생성, 변경 불가능한 업데이트 로직 등과 같은 일반적인 사용 사례를 단순화하는 유틸리티 포함

  2. Opinionated: 스토어 설정을 위한 좋은 기본값 제공, 가장 일반적으로 사용되는 Redux addons 내장

  3. Powerful: Immer 및 Autodux와 같은 라이브러리에서 영감을 얻어 mutative하게 작성해도 불변성 로직으로 작성 가능, 전체 상태 "슬라이스"를 자동으로 생성 가능

  4. Effective: 적은 코드로 많은 작업 수행 가능

설치

Create React App 사용(권장 방식)

npx create-react-app my-app --template redux
or cra-template-redux-typescript
npx create-react-app my-app --template redux-typescript

기존 앱에 추가
npm install @reduxjs/toolkit
or
yarn add @reduxjs/toolkit

포함된 항목

Redux Toolkit에는 다음 API가 포함됩니다.

  • configureStore()
    createStore를 단순화된 구성 옵션과 좋은 기본값을 제공하기 위해 래핑합니다. 슬라이스 리듀서를 자동으로 결합하고, 제공하는 Redux 미들웨어를 추가하고, redux-thunk를 기본적으로 포함하며, Redux DevTools Extension을 사용할 수 있습니다.
  • createReducer()
  • createAction()
  • createSlice()
    리듀서 함수의 객체, 슬라이스 이름, 초기 상태 값을 받아 해당 액션 생성자와 액션 타입으로 슬라이스 리듀서를 자동으로 생성합니다.
  • createAsyncThunk
  • createEntityAdapter

사용 방법

configureStore 를 사용하여 Redux 스토어 생성

  • configureStorereducer함수를 명명된 인수로 받습니다.
  • configureStore는 좋은 기본 설정으로 store를 자동으로 설정합니다.

Ex. app/store.js

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

// 1. Create a Redux Store
// 자동으로 Redux DevTools extension 설정 
export const store = configureStore({
  reducer: {},
});

React 애플리케이션 컴포넌트에 Redux 스토어 제공

  • React-Redux <Provider> 컴포넌트로<App /> 를 감싸줍니다.
  • Redux 스토어를 다음과 같이 전달합니다. <Provider store={store}>

Ex. index.js

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';
import * as serviceWorker from './serviceWorker';

// 2. Provide the Redux Store to React
ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

Redux "slice" 리듀서 생성 createSlice

  • createSlice를 불러와 문자열 이름, 초기 상태 및 명명된 리듀서 함수와 함께 사용합니다.
  • 리듀서 함수는 Immer를 사용하여 상태를 변형할 수 있습니다.
  • 생성된 slice 리듀서 및 액션 생성자를 내보냅니다.

Ex. counterSlice.js

import { createSlice } from '@reduxjs/toolkit'

// 3. Create a Redux State Slice 리덕스 상태 슬라이스 생성
// 슬라이스를 만들려면 슬라이스를 식별하는 'name: 문자열 이름', 'initialState: 초기 상태값', '상태 업데이트 방법을 정의하는 하나 이상의 reducer 함수'가 필요 
// 슬라이스가 생성되면 생성된 redux 액션 생성자와, 전체 슬라이스에 대한 reducer 함수를 내보낼 수 있다.  
// Redux Toolkit createSlice과 createReducerAPI는 
// Immer를 내부에서 사용하여 변경 불가능한 올바른 업데이트가 되는 "불변" 업데이트 로직을 작성
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  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
    },
  },
})

// 각 케이스 리듀서 함수에 대해 액션 생성자 생성
export const { increment, decrement, incrementByAmount } = counterSlice.actions

// coutnerSlice의 reducer를 내보냄(default로 설정해서 다른 이름으로 받을수 o)
export default counterSlice.reducer

스토어에 슬라이스 리듀서 추가

다음으로 counterSlice 에서 리듀서 함수를 가져 와서 스토어에 추가해야 합니다. 리듀서 매개 변수 내부에 필드를 정의하여 해당 상태에 대한 모든 업데이트를 처리하기 위해 이 슬라이스 리듀서 함수를 사용하도록 스토어에 지시합니다.

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

export default configureStore({
  reducer: {
    counter: counterReducer,
  },
})

리액트 컴포넌트에서 React-Redux의 useSelector/useDispatchReact 훅을 이용해 Redux 상태 및 액션 사용

이제 React-Redux 훅을 사용하여 React 컴포넌트가 Redux 스토어와 상호 작용하도록 할 수 있습니다.

  • useSelector 훅을 사용하여 스토어에서 데이터 읽기
  • dispatch 함수를 useDispatch 훅에서 가져오고 필요에 따라 액션을 전달합니다.
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 버튼 클릭할 때마다, 
// 해당하는 redux action이 스토어로 발송(dispatch)
// counter slice reducer는 actions를 보고 상태 업데이트 
// <Counter> 컴포넌트는 스토어로부터 전달된 새로운 상태값을 보고, 새로운 데이터 자체를 리렌더링

0개의 댓글