[React] Redux-Toolkit 사용하기

seung·2022년 6월 18일
1

설치


Redux Toolkit을 아래 명령어를 입력해 설치한다.

만약 기존에 redux가 설치되어 있다면 redux 패키지를 삭제한다.

→ Redux Toolkit에 redux가 포함되어 있기 때문

$ npm install @reduxjs/toolkit react-redux

사용방법


스토어 파일로 가서 createSlice 함수를 임포트한 뒤, 속성 객체를 매개변수로 넣어준다.

스토어와 연결하기 위해서는 configureStore를 이용하여 연결해준다.

(→ 여러 리듀서를 하나의 리듀서로 쉽게 합칠 수 있다.)

그리고 액션 객체들을 counterSlice.actions를 이용하여 내보내준다.

  • name: 고유한 이름
  • initialState: state의 초기값
  • reducers: 리듀서 함수들 정의
    • 기존에는 if문으로 분기를 해주었지만 리덕스 툴킷에서는 함수로 따로 선언해줌
import { createSlice, configureStore } from '@reduxjs/toolkit';

const initialState = { counter: 0, showCounter: true };

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment(state) {
      state.counter++;
    },
    decrement(state) {
      state.counter--;
    },
    increase(state, action) {
      state.counter = state.counter + action.payload.amount;
    },
    toggleCounter(state) {
      state.showCounter = !state.showCounter;
    },
  },
});

const store = configureStore({
  reducer: counterSlice.reducer,
});

export const counterActions = counterSlice.actions;
export default store;

이전에 redux 설명할 때 reducer에서 state를 반환할 때 절대 원본 state를 변경하면 안되고 새로운 state객체를 반환해야 한다고 했다.

그런데 위의 코드에서는 새로운 객체를 반환하는 형태가 아닌 state를 변경하는 형태이다.

redux toolkit에서는 원본 state객체를 변경해도 되는 것일까? 그것은 아니다!

여기에서도 여전히 원본 state 객체를 바꿀 수는 없다.

그러나 redux toolkit과 createSlice와 같은 함수를 사용하면 기존 상태를 바꿀 수 없다.

왜냐하면 redux toolkit은 내부적으로 immer라는 다른 패키지를 사용하는데 이런 코드를 감지하고 자동으로 원래 잇는 상태를 복제한다.

그리고 새로운 상태 객체를 생성하고 모든 상태를 변경할 수 없게 유지하고, 우리가 변경한 상태는 변하지 않도록 오버라이드한다.

그래서 위와 같이 state.count++ 처럼 변경을 해도 겉으로는 보이지 않지만 내부적으로는 원본 상태를 복제하여 오버라이드 해주는 것이다.


import { useSelector, useDispatch } from 'react-redux';

import { counterActions } from '../store/index';

import classes from './Counter.module.css';

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const show = useSelector((state) => state.showCounter);

  const incrementHandler = () => {
    dispatch(counterActions.increment());
  };

  const increaseHandler = () => {
    dispatch(counterActions.increase({ amount: 5 }));
  };

  const decrementHandler = () => {
    dispatch(counterActions.decrement());
  };

  const toggleCounterHandler = () => {
    dispatch(counterActions.toggleCounter());
  };

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {show && <div className={classes.value}>{counter}</div>}
      <div>
        <button onClick={incrementHandler}>Increment</button>
        <button onClick={increaseHandler}>Increase by 5</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

다중 슬라이스 작업하기

counter에 관련된 슬라이스와 auth에 관련된 슬라이스를 분리하여 생성한다.

그리고 configureStore 설정하는 부분의 reducer에 각각의 슬라이스를 객체로 지정해준다.

리듀서를 객체로 지정하면 나중에 하나의 주요 리듀서로 자동으로 합쳐지면서 받게 된다.

마지막으로 authSlice의 액션들도 export 해주면 된다.

import { createSlice, configureStore } from '@reduxjs/toolkit';

const initialCounterState = { counter: 0, showCounter: true };

const counterSlice = createSlice({
  name: 'counter',
  initialState: initialCounterState,
  reducers: {
    increment(state) {
      state.counter++;
    },
    decrement(state) {
      state.counter--;
    },
    increase(state, action) {
      state.counter = state.counter + action.payload.amount;
    },
    toggleCounter(state) {
      state.showCounter = !state.showCounter;
    },
  },
});

const initialAuthState = {
  isAuthenticated: false,
}

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    }
  }
});

const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
    auth: authSlice.reducer,
  },
});

export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;

export default store;

스토어 파일 분리하기

역할에 따라 스토어 파일을 분리하여 관리하면 좀 더 보기 쉽고 관리가 쉽다.

createSlice로 적용한 코드를 따로 파일로 분리한다.

위의 파일의 경우에는 counter.jsauth.js를 따로 파일로 만들어서 counter에 관련된 부분과 사용자 인증에 관련된 부분을 나누어 준다.

❗️분리한 파일 내에서 슬라이스의 리듀서를 default export한다.

❗️분리한 파일 내에서 액션을 export한다.

import { createSlice } from '@reduxjs/toolkit';

const initialCounterState = { counter: 0, showCounter: true };

const counterSlice = createSlice({
  name: 'counter',
  initialState: initialCounterState,
  reducers: {
    increment(state) {
      state.counter++;
    },
    decrement(state) {
      state.counter--;
    },
    increase(state, action) {
      state.counter = state.counter + action.payload.amount;
    },
    toggleCounter(state) {
      state.showCounter = !state.showCounter;
    },
  },
});

export const counterActions = counterSlice.actions;

export default counterSlice.reducer;
import { createSlice } from '@reduxjs/toolkit';

const initialAuthState = {
  isAuthenticated: false,
};

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    },
  },
});

export const authActions = authSlice.actions;

export default authSlice.reducer;

스토어의 메인이 되는 index.js 파일에서는 리듀서를 임포트하여 store를 만들고 내보내주는 역할만 한다.

import { configureStore } from '@reduxjs/toolkit';

import counterReducer from './counter';
import authReducer from './auth';

const store = configureStore({
  reducer: {
    counter: counterReducer,
    auth: authReducer,
  },
});

export default store;
profile
🌸 좋은 코드를 작성하고 싶은 프론트엔드 개발자 ✨

0개의 댓글