티스토리 뷰

Redux 공식문서에서 Redux Toolkit 사용을 공식적으로 적극 추천한다. 기존 Redux에서 작업을 단순화하고, 흔한 실수를 방지하여 Redux 어플리케이션을 더 쉽게 만들 수 있도록 한다.

기존의 Redux를 React, vanillaJS에서 사용하는 방법은 각각 다음의 포스팅에서 확인할 수 있다.

 

Redux란 / Redux React에서 사용하기

Redux는 JavaScript 어플리케이션의 상태를 관리할 수 있는 상태 관리 라이브러리이다.(React, Vue, Angular, vanilla JS 등 모두 사용할 수 있다.) React로 상태 관리를 할 때 props drilling이나 상태끌어올리기를

hahagarden.tistory.com

 

Redux vanillaJS에서 사용하기

html파일에서 간단하게 증감버튼을 만들고, JavaScript파일로 DOM조작을 하고, Redux로 상태를 관리한다. add minus DOM조작을 위해 브라우저 환경에서 작업하였다. 리액트를 주로 사용했어서 자연스럽게

hahagarden.tistory.com

 

createAction

function createAddAction(text){
    return {
        type: 'add',
        payload: text
    }
}

const action = createAddAction('hello')

우리는 위와 같이 액션 생성자를 정의해주었다. 액션마다 function, return, type:, payload: 등을 입력해주는 것은 귀찮고 비효율적인 일이다. Redux Toolkit에서는 이러한 반복적인 작업을 해주지 않고 다음과 같이 두 줄만으로 원하는 action을 생성할 수 있다.

const actionAddCreator = createAction('add');
const action = actionAddCreator('hello'); // { type: 'add', payload: 'hello' }

console.log(actionAddCreator); // function
console.log(actionAddCreator.type); // 'add'
console.log(actionAddCreator()); // { type: 'add', payload: undefined }

 

createReducer

createReducer을 사용하는 방법은 Redux 공식문서를 참고할 수 있다. 그 중에서 소개할 것은 위에서 살펴본 createAction과 결합해서 사용할 수 있는 아주 간편한 방법이다.

const addToDo = createAction('add');
const deleteToDo = createAction('delete');

const reducer = createReducer([], {
    [addToDo]: (state, action) => { state.push(action.payload) }
    [deleteToDo]: (state, action) => state.filter(toDo => toDo !== action.payload)
};
// first argument [] is initialState.
// key of second argument object is action-name created by createAction.
// createReducer has two options if state is not primitive value,
// 1. just mutate state like [addToDo]
// 2. return new state like [deleteToDo]

 

configureStore

configureStore은 더 나은 개발자 경험을 위해 createStore에 몇 가지 기본 설정을 추가해놓은 함수이다. 그래서 configureStore로 생성한 store은 추가작업을 해주지 않아도 자동으로 Redux developer tools를 사용할 수 있다.
configureStore의 전달인자로 reducer 프로퍼티를 가진 객체를 전달해주며, 다음과 같이 하나의 상태만 다룰 수도 있고 여러 개의 상태를 다룰 수 있다.

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

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

export default store
import { configureStore } from '@reduxjs/toolkit'
import usersReducer from './usersReducer'
import postsReducer from './postsReducer'

const store = configureStore({
  reducer: {
    users: usersReducer,
    posts: postsReducer,
  },
})

export default store

 

createSlice

createSlice로 한 번에 reducer와 action을 생성할 수 있다. 아예 action을 정의하거나 action 생성자를 만들지 않는다. reducer만 정의해주면 createSlice가 actions와 reducer를 제공한다.

// counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: { value: 0 }, // not primitive value
  reducers: {
    add: (state) => {
      state.value++;
    },
    minus: (state, action) => {
      state.value--;
    },
    setDefault: (state, action) => {
      state.value = action.payload;
    },
  },
}); // counterSlice has reducer and actions like below

export const { add, minus, setDefault } = counterSlice.actions; // actionCreator: (payload) => { type: name/actionCreator, payload }

export default counterSlice.reducer;
// store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";

const store = configureStore({ reducer: { counter: counterReducer } }); // useSelector( state => state.counter ) 으로 사용

export default store;
// App.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { add, minus, setDefault } from "./counterSlice"; // ActionCreators

function App() {
  const counter = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  const onAddClick = () => {
    dispatch(add());
  };

  const onMinusClick = () => {
    dispatch(minus());
  };

  const onSetDefaultClick = () => {
    dispatch(setDefault(0));
  }; // payload 0

  return (
    <div>
      <button onClick={onAddClick}>add</button>
      <span>{counter}</span>
      <button onClick={onMinusClick}>minus</button>
      <button onClick={onSetDefaultClick}>reset</button>
    </div>
  );
}

export default App;

 

combinedReducers

Redux 공식문서에 따라, 상태를 여러가지 관리하고 있을 때 combinedReducers에게 모든 상태의 reducer를 value로 하고, 그들에게 각각 부여할 상태 이름을 key로 하여 객체를 만들어 전달인자로 전달하면 더욱 간편하게 상태를 사용할 수 있다. 다음과 같이 작성한다.

// store.js
// createSlice로 각각 savedTodosReducer와 todayTodosReducer를 만들었다고 했을 때,

const { configureStore, combineReducers } = require('@reduxjs/toolkit');
import savedTodosReducer from './savedTodosSlice';
import todayTodosReducer from './todayTodosSlice';

const reducer = combineReducers({ todayTodos: todayTodosReducer, savedTodos: savedTodosReducer });

const store = configureStore({ reducer });

export default store;

 

🔨 createReducer.ts:283 Uncaught Error: A case reducer on a non-draftable value must not return undefined
 createSlice의 전달인자 initialState를 원시값으로 지정했을 때 나오는 에러이다. createReducer 또는 createSlice를 사용할 때 초기값을 배열 또는 객체로 지정해주어야 한다.

 

 

반응형
댓글