• React

[Redux] Redux & Redux-toolkit

man_on 2022. 2. 13. 17:53
๋ฐ˜์‘ํ˜•

 

 

 

     


     

    What is "Redux" ?

     

     

    ๐Ÿ”ป A state management system for cross-component or app-wide state.

     

     

    โœ”๏ธ  state๋ฅผ 3์ข…๋ฅ˜๋กœ ํฌ๊ฒŒ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

    1. Local state : ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ์— ์ข…์†๋˜๋Š” state

    2. Cross-Component state : ํ•˜๋‚˜ ์ด์ƒ์˜ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” state(prop drilling)

    3. App-Wide state : app์ „์ฒด์˜ ๊ธฐ๋ณธ์ ์ธ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” state 

     

     

    ๐Ÿคท๐Ÿป‍โ™€๏ธ   React Context๋„ ์žˆ๋Š”๋ฐ ์™œ Redux? context API์˜ ๋‹จ์ 

     > ๋Œ€๊ทœ๋ชจ์˜ app์ž‘์—… ์‹œ state๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด

          : ์ˆ˜๋งŽ์€ context provider ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ค‘์ฒฉ๋˜์–ด ๋ณต์žกํ•ด์ง„๋‹ค.

          : provider๊ฐœ์ˆ˜๋ฅผ ์ค„์ด๊ณ  ํ•˜๋‚˜์˜ ๊ฑฐ๋Œ€ํ•œ context provider๋กœ๋Š” ๊ด€๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ

     > state ๋ณ€๋™ ํšŸ์ˆ˜๊ฐ€ ๋†’์€ ๊ฒฝ์šฐ์— ์„ฑ๋Šฅ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

     

     

     

     

     

     


     

     

     

     

     

    Redux ๊ธฐ๋ณธ ์ž‘๋™ ๋ฐฉ์‹

     

     

     

    Redux๋Š” app์— ํ•˜๋‚˜์˜ ์ค‘์•™ ๋ฐ์ดํ„ฐ(state) ์ €์žฅ์†Œ๋ฅผ ๊ฐ€์ง„๋‹ค.  ( app์ „์ฒด๋ฅผ ์œ„ํ•œ ํ•˜๋‚˜์˜ store! )

     

    ์ „์—ญ์ƒํƒœ๋ฅผ ํ•˜๋‚˜์˜ ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๋ฉฐ, action(์–ด๋–ค ์ƒํƒœ๋ณ€๊ฒฝ์ด ์ƒ๊ธธ์ง€ ์„œ์ˆ ํ•˜๋Š” ๊ฐ์ฒด)์„ ๋‚ด๋ณด๋‚ด์„œ(dispatch) ์ƒํƒœ๋ณ€๊ฒฝ์„ ํ•œ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  action์ด ์ „์ฒด application์˜ ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ• ์ง€ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•ด์„œ reducer์˜ ์ž‘์„ฑ์ด ํ•„์š”ํ•˜๋‹ค.

     

     

     

     

    ๐Ÿ”ป Redux ํ๋ฆ„

    1. component๊ฐ€ ํŠน์ • action์„ trigger ( action์€ ๋‹จ์ˆœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด - reducer๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์˜ ์ข…๋ฅ˜๋ฅผ ์„ค๋ช… )

    2. actions์„ reducer๋กœ ์ „๋‹ฌํ•˜์—ฌ ์›ํ•˜๋Š” ์ž‘์—… ํ˜ธ์ถœ 

    3. reducer๋Š” ์ค‘์•™๋ฐ์ดํ„ฐ store์— ์กด์žฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ต์ฒดํ•˜๋Š” ์ƒˆ๋กœ์šด state๋ฅผ ๋ณด๋ƒ„

    4. ๋ฐ์ดํ„ฐ store์— ์žˆ๋Š” state๊ฐ€ update

    5. subscribeํ•˜๋Š” component์— ์•Œ๋ ค์ ธ UI update

     

     

     

     

     

    โœ”๏ธ  Reducer function

      ํ•ญ์ƒ ๋‘๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ (๊ธฐ์กด์ƒํƒœ์™€ dispatched action)๋ฅผ ์ž…๋ ฅ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฆฌํ„ดํ•ด์•ผํ•œ๋‹ค.

      ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜์ด๋‹ค. (์ž…๋ ฅ๊ณผ value๊ฐ€ ๊ฐ™๋‹ค๋ฉด ํ•ญ์ƒ ๊ฐ™์€ ์ถœ๋ ฅ์„ ์ƒ์‚ฐํ•œ๋‹ค.)

     

     

     

    const redux = require("redux");
    
    //reducer function
    const counterReducer = (state = { counter: 0 }, action) => {
      if (action.type === "increment") {
        return {
          counter: state.counter + 1,
        };
      }
      if (action.type === "decrement") {
        return {
          counter: state.counter - 1,
        };
      }
    };
    
    //central Data Store
    const store = redux.createStore(counterReducer);
    
    //Subscription
    const counterSubscriber = () => {
      const latestSate = store.getState();
      console.log(latestSate);
    };
    
    store.subscribe(counterSubscriber);
    
    store.dispatch({ type: "increment" });
    store.dispatch({ type: "decrement" });
    
    //์ถœ๋ ฅ
    { counter : 1 }
    { counter : 0 }

     

     

     

     

     


     

     

     

     

     

    Redux ์‚ฌ์šฉ

     

     

     

    1. store์ƒ์„ฑ 

    store / index.js

    import { createStore } from "redux";
    
    const counterReducer = (state = { counter: 0 }, action) => {
      if (action.type === "increment") {
        return {
          counter: state.counter + 1,
        };
      }
      if (action.type === "decrement") {
        return {
          counter: state.counter - 1,
        };
      }
      return state;
    };
    
    const store = createStore(counterReducer);
    
    export default store;

     

     

     

    2. ๊ฐ€์žฅ ๋†’์€ component ๋ ˆ๋ฒจ์—์„œ store ์ œ๊ณต

    provider๋กœ ๊ฐ์‹ธ์ฃผ๊ณ  ์œ„์—์„œ store๋ฅผ props๋กœ ๋„˜๊ฒจ์ค€๋‹ค.

    Index.js
    
    //import React from "react";//
    //import ReactDOM from "react-dom";
    import { Provider } from "react-redux";
    //import App from "./App";
    import store from "./store/index";
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById("root")
    );

     

     

    3. react component์—์„œ redux data ์‚ฌ์šฉ

        useSelector hook์œผ๋กœ store์—์„œ state๊ฐ€์ ธ์˜ค๊ณ , 

        useDispatch hook์œผ๋กœ redux store์— ๋Œ€ํ•œ action์„ ๋ณด๋‚ธ๋‹ค.

    import { useSelector, useDispatch } from "react-redux";
    
    const Counter = () => {
      const dispatch = useDispatch();
      const counter = useSelector((state) => state.counter);
    
      const incerementHandler = () => {
        dispatch({ type: "increment" });
      };
      const decerementHandler = () => {
        dispatch({ type: "decrement" });
      };
    
      return (
        <main className={classes.counter}>
          ...
          <div>
            <button onClick={incerementHandler}>Increment</button>
            <button onClick={decerementHandler}>Decrement</button>
          </div>
          ...
        </main>
      );
    };
    
    export default Counter;

     

     

    ๐Ÿ“Œ  payload 

         action์— ์†์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ

         (reducer์—์„œ ํ•˜๋“œ์ฝ”๋”ฉ ํ•˜์ง€์•Š๊ณ  action์œผ๋กœ๋ถ€ํ„ฐ ๊ฐ’์„ ์–ป์–ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พผ๋‹ค.)

     

      if (action.type === "increase") {
        return {
          counter: state.counter + action.amount,
        };
      }
    const Counter = () => {
      const dispatch = useDispatch();
      const counter = useSelector((state) => state.counter);
    
    
      const increseHandler = () => {
        dispatch({ type: "increase", amount: 10 });
      };
    
    
      return (
        <main className={classes.counter}>
             ...
            <button onClick={increseHandler}>Increse</button>
             ...
        </main>
      );

     

     

     

     

    ๐Ÿ’ฅ   ์—ฌ๋Ÿฌ state ์†์„ฑ ์ž‘์—…

          : Reducer์—์„œ state ์ถ”๊ฐ€

     

    > store์—์„œ ๊ธฐ์กด counter์—์„œ showCounter์ถ”๊ฐ€

    //store-index.js
    const initialState = { counter: 0, showCounter: true };
    const counterReducer = (state = initialState, action) => {
      if (action.type === "toggle") {
        return {
          showCounter: !state.showCounter,
          counter: state.counter,
        };
      }
      ...

     

    const Counter = () => {
      const dispatch = useDispatch();
      const counter = useSelector((state) => state.counter);
      const show = useSelector((state) => state.showCounter);
    
      const toggleCounterHandler = () => {
        dispatch({ type: "toggle" });
      };
    
      return (
        <main className={classes.counter}>
          {show && <div className={classes.value}>{counter}</div>}
           ...
           <button onClick={toggleCounterHandler}>Toggle Counter</button>
        </main>
      );
    };

     

     

     

     

     

     


     

     

     

     

     

     

    Redux toolkit 

     

     

     

    ๐Ÿ”ป redux๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ๋‚˜์˜จ ๋„๊ตฌ๋ชจ์Œ!

        redux๋กœ์ง์„ ์ž‘์„ฑํ•˜๋Š” ํ‘œ์ค€ ๋ฐฉ์‹์ด ๋˜๊ธฐ ์œ„ํ•œ ์˜๋„๋กœ ๋งŒ๋“ค์–ด ์กŒ๋‹ค.

        ํ•ต์‹ฌ์€ ๊ธฐ์กด ๋ฆฌ๋•์Šค์˜ ๋ณต์žกํ•จ์„ ๋‚ฎ์ถ”๊ณ  ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ๊ฒƒ์ด๋‹ค.

     

        

     

    ๋ฆฌ๋•์Šค์˜ ๋Œ€ํ‘œ์ ์ธ ๋ฌธ์ œ

    - store ํ™˜๊ฒฝ์„ค์ •์ด ๋ณต์žกํ•˜๋‹ค.

    - ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋งŽ์€ ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

    - ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ (์–ด๋–ค ์ผ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๊ผญ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ)๋ฅผ ๋งŽ์ด ์š”๊ตฌํ•œ๋‹ค.

     

     

     

    โœ”๏ธ toolkit์— redux๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋˜์–ด์žˆ์–ด์„œ, toolkt์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ธฐ์กด์— ์„ค์น˜๋œ redux๋ฅผ ์‚ญ์ œํ•ด์ค€๋‹ค.

    npm i @reduxjs/toolkit

     

     

    https://redux-toolkit.js.org/

     

    Redux Toolkit | Redux Toolkit

    The official, opinionated, batteries-included toolset for efficient Redux development

    redux-toolkit.js.org

     

     

     

     

     

     


     

     

     

     

     

     

    Redux toolkit ์‚ฌ์šฉ

     

     

     

     

    1.  createSlice

          ๋ฆฌ๋•์Šค ๋กœ์ง ์ž‘์„ฑ ์‹œ ducks pattern ํ˜•ํƒœ๋กœ ์ž‘์„ฑ์„ ๋•๋Š” createSlice๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

         ํŠน์ง•

          - ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ์„œ ์ƒ์„ฑ.

          - ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์›€.

          - ๋”ฐ๋กœ ์ƒํƒœ๋ฅผ ๋ณต์‚ฌํ•˜์ง€์•Š๊ณ  ๋ฐ”๋กœ ๋ณ€๊ฒฝ๊ฐ€๋Šฅ

           (toolkit๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ immer๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ž๋™์œผ๋กœ ์›๋ž˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ๋ณต์ œ)

          - ์ƒํƒœ์™€ํ•จ๊ป˜ action๋„ ๋ฐ›์Œ (action.payload)

    import { createSlice } from "@reduxjs/toolkit";
    const initialCounterState = { counter: 0, showCounter: true };
    
    const counterSlice = createSlice({
      name: "counter",   //๋ชจ๋“  slice๋Š” name๊ฐ€์ ธ์•ผํ•จ(์ƒํƒœ์‹๋ณ„์ž)
      initialState: initialCounterState,  //์ดˆ๊ธฐ๊ฐ’์„ค์ •
      reducers: {
        //๊ธฐ์กด์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด์•„๋‹˜, ์ž๋™์œผ๋กœ ๊ธฐ์กด์˜ ์ƒํƒœ๋ฅผ ๋ณต์ œํ•ด์„œ ๋ณ€ํ˜•์‹œํ‚ด (๋ถˆ๋ณ€์„ฑ ์‹ ๊ฒฝ์“ธ ํ•„์š”์—†์–ด์ง)
        increment(state) {
          state.counter++;
        },
        decrement(state) {
          state.counter--;
        },
        increase(state, action) {
          state.counter = state.counter + action.payload;
        },
        toggleCounter(state) {
          state.showCounter = !state.showCounter;
        },
      },
    });

     

     

     

     

     

    2.  configureStore

        : ์Šคํ† ์–ด๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํ•จ์ˆ˜์ด๋ฉฐ,  ์—ฌ๋Ÿฌ๊ฐœ์˜ reducer๋ฅผ ํ•˜๋‚˜์˜ reducer๋กœ ์‰ฝ๊ฒŒ ํ•ฉ์น  ์ˆ˜ ์žˆ๋‹ค.

          ์—ฌ๋Ÿฌ slice๋ฅผ ๋‚ด๋ณด๋‚ผ ๋•Œ๋Š” ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด์„œ key๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ ๋ณด๋‚ธ๋‹ค.

          (๊ธฐ์กด reduxdml combineReducers ํ•จ์ˆ˜์™€ ๊ฐ™์€์—ญํ• )

     

          ๋ฆฌ๋•์Šค ์ฝ”์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ‘œ์ค€ ํ•จ์ˆ˜์ธ createStore๋ฅผ ์ถ”์ƒํ™”ํ•œ ๊ฒƒ์ด๋‹ค.

          (๊ธฐ์กด ๋ฆฌ๋•์Šค์˜ ๋ฒˆ๊ฑฐ๋กœ์šด ๊ธฐ๋ณธ ์„ค์ •๊ณผ์ •์„ ์ž๋™ํ™”)

    import { createSlice, configureStore } from "@reduxjs/toolkit";
    
    const counterSlice = createSlice({
      ...
    )}
    
    const store = configureStore({
      reducer: counterSlice.reducer,
    });
    
    export const counterActions = counterSlice.actions;

    slicename.actions.keyname = actions ์ƒ์„ฑ์ž

    ( ex. counterSlice.actions.increment > ์•ก์…˜์ „๋‹ฌ )

     

     

     

     

     

    3. state๋ฅผ ์‚ฌ์šฉํ•  component์—์„œ import 

     

    import { counterActions } from "../store/index";
    import { useSelector, useDispatch } from "react-redux";
    import { counterActions } from "../store/index";
    
    const Counter = () => {
      const dispatch = useDispatch();
      const counter = useSelector((state) => state.counter);
      const show = useSelector((state) => state.showCounter);
      //store์—์„œ key๊ฐ’ ์„ค์ •์„ ํ•˜์ง€์•Š์•˜๋‹ค๋ฉด state.counter
      //key๊ฐ’ ์„ค์ •์„ ํ–ˆ์œผ๋ฉด key๊ฐ’์„ ์ถ”๊ฐ€ํ•ด์„œ state.key.counter
    
      const incerementHandler = () => {
        dispatch(counterActions.increment());
      };
      const decerementHandler = () => {
        dispatch(counterActions.decrement());
      };
      const increseHandler = () => {
        //{type:SOME_UNIQUE+IDENTIFIER, payload : 10}
        //payload๋Š” toolkit๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ•„๋“œ๋ช…
        dispatch(counterActions.increase(10));
      };
      const toggleCounterHandler = () => {
        dispatch(counterActions.toggleCounter());
      };

     

    payload๊ฐ€ ํ•„์š”ํ•  ์‹œ ๊ฐ’์„ ๊ด„ํ˜ธ์— ์ „๋‹ฌํ•ด ์ฃผ๊ณ , reducer์—์„œ action.payload๋กœ ์ ‘๊ทผํ•œ๋‹ค.

    ( toolkit๋Š” ์ž๋™์œผ๋กœ action ์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑํ•ด์„œ redux toolkit๊ฐ€ ์ƒ์„ฑํ•œ type: SOME_UNIQUE_IDENTIFIER์„ ์ „๋‹ฌํ•˜๊ณ ,

      ์ธ์ž๋กœ์„œ ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ์•ก์…˜ ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•œ ๊ฐ’์„ ์ถ”๊ฐ€ ํ•„๋“œ๋ช…์ด payload์ธ ๊ณณ์— ์ €์žฅํ•œ๋‹ค.)

     

     

     

     

     

     

    4. ์—ฌ๋Ÿฌ slice๊ด€๋ฆฌ

        ์œ„ ๊ณผ์ •๊ณผ ๋™์ผํ•˜๊ฒŒ slice๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  store์— ์ถ”๊ฐ€๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

        ( slice๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๋ผ๋„ redux store๋Š” ํ•˜๋‚˜๋ฐ–์ด์–ด์„œ configureStore๋ฅผ ํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค! )

     

    const AuthSlice = createSlice({
      name: "authentication",
      initialState: { isAuthenticated: false },
      reducers: {
        login(state) {
          state.isAuthenticated = true;
        },
        logout(state) {
          state.isAuthenticated = false;
        },
      },
    });
    
    const store = configureStore({
      reducer: { counter: counterSlice.reducer, auth: AuthSlice.reducer },
    });
    
    export const authActions = authSlice.actions;

     

     

     

    ๋”๋ณด๊ธฐ
    //store/index.js
    // import { createStore } from "redux";
    //slice๋Š” createReducer๋ณด๋‹ค ๊ฐ•๋ ฅํ•˜๊ณ  ํ•œ๋ฒˆ์— ๋ช‡๊ฐ€์ง€๋ฅผ ๋‹จ์ˆœํ™”ํ•œ๋‹ค.
    import { createSlice, configureStore } from "@reduxjs/toolkit";
    
    const initialCounterState = { counter: 0, showCounter: true };
    
    const counterSlice = createSlice({
      //์ „์—ญ์ƒํƒœ์˜ slice๋ฅผ ๋ฏธ๋ฆฌ๋งŒ๋“ ๋‹ค
      name: "counter",
      initialState: initialCounterState, //์ดˆ๊ธฐ๊ฐ’์„ค์ •
      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 authSlice = createSlice({
      name: "authentication",
      initialState: { isAuthenticated: false },
      reducers: {
        login(state) {
          state.isAuthenticated = true;
        },
        logout(state) {
          state.isAuthenticated = false;
        },
      },
    });
    // const counterReducer = (state = initialState, action) => {
    //   if (action.type === "increment") {
    //     return {
    //       counter: state.counter + 1,
    //       showCounter: state.showCounter,
    //     };
    //   }
    //   if (action.type === "decrement") {
    //     return {
    //       counter: state.counter - 1,
    //       showCounter: state.showCounter,
    //     };
    //   }
    
    //   if (action.type === "increase") {
    //     return {
    //       counter: state.counter + action.amount,
    //       showCounter: state.showCounter,
    //     };
    //   }
    
    //   if (action.type === "toggle") {
    //     return {
    //       showCounter: !state.showCounter,
    //       counter: state.counter,
    //     };
    //   }
    //   return state;
    // };
    
    const store = configureStore({
      reducer: { counter: counterSlice.reducer, auth: authSlice.reducer },
    });
    // configureStore๋กœ ์—ฌ๋Ÿฌ slice๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
    // ์—ฌ๋Ÿฌ๊ฐœ ๋‚ด๋ณด๋‚ผ๋•Œ๋Š” ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด์„œ key๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ์„œ ๋ณด๋‚ธ๋‹ค.
    // reducer : {counter : counterSlice.reduce}
    export const counterActions = counterSlice.actions;
    export const authActions = authSlice.actions;
    
    export default store;

     

    //Counter.js
    import classes from "./Counter.module.css";
    import { useSelector, useDispatch } from "react-redux";
    import { counterActions } from "../store/index";
    
    const Counter = () => {
      const dispatch = useDispatch();
      const counter = useSelector((state) => state.counter.counter);
      const show = useSelector((state) => state.counter.showCounter);
    
      const incerementHandler = () => {
        dispatch(counterActions.increment());
      };
      const decerementHandler = () => {
        dispatch(counterActions.decrement());
      };
      const increseHandler = () => {
        //{type:SOME_UNIQUE+IDENTIFIER, payload : 10}
        //payload๋Š” toolkit๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ•„๋“œ๋ช…
        dispatch(counterActions.increase(10));
      };
      const toggleCounterHandler = () => {
        dispatch(counterActions.toggleCounter());
      };
    
      return (
        <main className={classes.counter}>
          <h1>Redux Counter</h1>
          {show && <div className={classes.value}>{counter}</div>}
          <div>
            <button onClick={incerementHandler}>Increment</button>
            <button onClick={decerementHandler}>Decrement</button>
            <button onClick={increseHandler}>Increse</button>
          </div>
          <button onClick={toggleCounterHandler}>Toggle Counter</button>
        </main>
      );
    };
    
    export default Counter;
    
    // class Counter extends Component {
    //   incerementHandler() {
    //     this.props.increment();
    //   }
    //   decerementHandler() {
    //     this.props.decrement();
    //   }
    //   toggleCounterHandler() {}
    //   render() {
    //     return (
    //       <main className={classes.counter}>
    //         <h1>Redux Counter</h1>
    //         <div className={classes.value}>{this.props.counter}</div>
    //         <div>
    //           <button onClick={this.incerementHandler.bind(this)}>Increment</button>
    //           <button onClick={this.decerementHandler.bind(this)}>Decrement</button>
    //         </div>
    //         <button onClick={this.toggleCounterHandler}>Toggle Counter</button>
    //       </main>
    //     );
    //   }
    // }
    // const mapStateToProps = (state) => {
    //   return {
    //     counter: state.counter,
    //   };
    // };
    
    // const mapDispatchToProps = (dispatch) => {
    //   return {
    //     increment: () => dispatch({ type: "increment" }),
    //     decrement: () => dispatch({ type: "decrement" }),
    //   };
    // };
    // export default connect(mapStateToProps, mapDispatchToProps)(Counter);

     

    ๋ฐ˜์‘ํ˜•