스파르타코딩클럽 내일배움캠프 TIL32

한재창·2022년 12월 13일
0

Redux와 ReduxToolkit

store/index.js

  • toolkit 을 사용하지 않았을 때 코드
    • 리액트 앱과 리덕스 스토어를 연결한다.
    • 앱의 컴포넌트가 디스패치하고 들을 수 있다.
    • 전체 순서 store/index.js > index.js > components/counter.js
import { createStore } from "redux";

// 초기값에 showCounter이 있으므로 기본값을 리듀서에서도 return할 때 주어야한다.
// return에 showCounter의 값을 주지 않으면 undefined가 되고 결국 true가 아니라서 화면에서 사라진다.
// 절대 기존의 state를 변경하면 안된다. (ex: return state.counter++)
const initialState = { counter: 0, showCounter: true };

const counterReducer = (state = initialState, action) => {
  if (action.type === "increment") {
    return {
      counter: state.counter + 1,
      showCounter: state.showCounter,
    };
  }

  // 현재 상태에서 payload의 값을 더해준다.
  if (action.type === "increase") {
    return {
      counter: state.counter + action.payload,
      showCounter: state.showCounter,
    };
  }

  if (action.type === "decrement") {
    return {
      counter: state.counter - 1,
      showCounter: state.showCounter,
    };
  }

  if (action.type === "toggle") {
    return {
      showCounter: !state.showCounter,
      counter: state.counter,
    };
  }

  return state;
};

const store = createStore(counterReducer);

export default store;
  • toolkit 을 사용했을 때 코드
    • name, 기본값, reducers를 객체로 정의한다.
    • 위의 코드와는 다르게 툴킷을 이용하면 기존의 값을 변경해주는 것을 방지해줘서 state.counter++ 같은 코드를 사용해도 괜찮다.
import { createSlice, configureStore } from "@reduxjs/toolkit";

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

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

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

// 툴킷에서 제공되는 메서드를 호출한다.
// 호출되면 액션 객체가 자동으로 생성된다.
export const counterActions = counterSlice.actions;

export default store;

components/Counter.js

  • toolkit 을 사용하지 않았을 때 코드
    • useSelector을 사용하는 이유는 자동으로 구독을 해준다. 따라서 리덕스 저장소에서 데이터가 변경될 때마다 자동으로 업데이트 되고 최신 상태를 유지
    • useSelector을 사용해서 저장소가 관리하는 데이터에 액세스(이용) 할 수 있다.
    • useSelector가 받는 콜백 함수는 react-redux가 실행해준다.
    • useDispatch는 스토어에 대한 액션을 보낸다.
import { useSelector, useDispatch } from "react-redux";

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

const Counter = () => {
  const dispatch = useDispatch();

  // 리덕스 상태의 관리된 데이터를 콜백 함수에 넣고, 이 코드를 실행해 컴포넌트에 필요로하는 상태 부분을 받게 된다.
  // 그러면 useSelector 전체가 그 리턴된 값을 준다.
  // 여기에서는 리덕스가 관리하는 카운터인 counter의 상수 값을 받게 된다.
  const counter = useSelector((state) => state.counter);
  const show = useSelector((state) => state.showCounter);

  // 새로운 action을 보내기 위해 실행한다.
  // action은 유형 속성이 있는 객체이고, type은 reducer에 있는 action.type와 같아야한다.
  const incrementHandler = () => {
    dispatch({ type: "increment" });
  };

  // action에 payload의 키, 값을 설정해주고 store/index.js에서 + action.payload라고 해주면 2씩 증가한다.
  const increaseHandler = () => {
    dispatch({ type: "increase", payload: 2 });
  };

  const decrementHandler = () => {
    dispatch({ type: "decrement" });
  };

  const toggleCounterHandler = () => {
    dispatch({ type: "toggle" });
  };

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</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;
  • toolkit 을 사용했을 때 코드
    • 툴킷이 자동으로 해주는 것이 많아서 코드를 간단히 할 수 있다.
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(2));
  };

  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</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;
profile
취준 개발자

0개의 댓글