๐Ÿ”ฎ ๋ฐ”๋‹๋ผJS๋ฅผ Redux๋กœ ๋ฆฌํŒฉํ† ๋ง ํ•˜๊ธฐ

MOON HEEยท2023๋…„ 1์›” 6์ผ
0

๋ฐ๋ธŒ ์Šคํ† ์–ด๋ฅผ Redux๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๊ณ  ์žˆ๋‹ค. ๋ฐ”๋‹๋ผJS ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์ƒํƒœ๋ณ€๊ฒฝ์„ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ž‘์„ฑํ•ด์•ผํ–ˆ๋‹ค.

์ฒ˜์Œ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ๋Š” ๋ฐ”๋‹๋ผ์ด๊ธฐ ๋•Œ๋ฌธ์— Redux๋Š” ์•ˆ์“ฐ๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์ง€๋งŒ, ๋ฐ”๋‹๋ผ๋กœ ์ƒํƒœ๋ณ€๊ฒฝ์„ ํ•˜๋ ค๋ฉด ์ด๋ ‡๊ฒŒ ์ƒ๊ธด ์ฝ”๋“œ๋ฅผ ์“ฐ๊ฒŒ ๋œ๋‹ค...

if (i === 0) {
  	buttonLoginType[i + 1].classList.remove("on");
  	buttonLoginType[i].classList.remove("help");
  	buttonLoginType[i].classList.add("on");
  	buttonLoginType[i + 1].classList.add("help");
} else if (i === 1) {
  	buttonLoginType[i - 1].classList.remove("on");
  	buttonLoginType[i].classList.remove("help");
  	buttonLoginType[i].classList.add("on");
  	buttonLoginType[i - 1].classList.add("help");
}

๊ทธ๋ž˜์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์–ด๋Š์ •๋„ ์™„์„ฑํ•œ ์‹œ์ ์— ๋ฆฌ๋•์Šค๋ฅผ ๋„์ž…ํ•˜๊ฒŒ ๋๋‹ค. ์ฝ”๋“œ๊ฐ€ ์—„์ฒญ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ์žˆ๋‹ค!! ๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€



Redux๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์˜ˆ์ธก๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ด€๋ฆฌ ๋„๊ตฌ๋‹ค.

์ƒํƒœ์ •๋ณด๋ฅผ ์ค‘์•™์ง‘์ค‘์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๋Œ€๋ฆฌ์ธ(?)์„ ํ†ตํ•ด์„œ๋งŒ ์ƒํƒœ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„ํ•˜์ง€ ์•Š์€ state ๊ฐ’ ๋ณ€๊ฒฝ ๋ฌธ์ œ๋ฅผ ์‚ฌ์ „์ฐจ๋‹จํ•œ๋‹ค.

์ด๋Ÿฐ ์•„์ด๋””์–ด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด์ „์˜ ์ƒํƒœ๊นŒ์ง€ ๋ ˆ์ฝ”๋”ฉ๋˜๋Š” ๊ธฐ๋Šฅ๊ณผ hot ๋ชจ๋“ˆ ๋ฆฌ๋กœ๋”ฉ(์ฝ”๋“œ ์ˆ˜์ • ํ›„ ์ €์žฅํ•  ๋•Œ ์ „๋ถ€ ์ƒˆ๋กœ๊ณ ์นจ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ณ€๊ฒฝ๋ถ€๋ถ„๋งŒ ์ˆ˜์ •) ๊ธฐ๋Šฅ ๋•์— ์ธ๊ธฐ๊ฐ€ ๋งŽ์•„์กŒ๋‹ค๊ณ  ํ•œ๋‹ค.


๋™์ž‘์›๋ฆฌ


store๋Š” ์€ํ–‰์ด๊ณ  dispatch, subscribe, getState๋Š” ์ฐฝ๊ตฌ ์ง์›์ด๋‹ค. ์œ„์—์„œ ๋งํ•œ ๋Œ€๋ฆฌ์ธ์— ํ•ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜๋“ค์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ธˆ๊ณ ์ง€๊ธฐ๋กœ reducer๊ฐ€ ์žˆ๋‹ค.

state๋Š” ์ ˆ๋Œ€๋กœ ์ง์ ‘ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋Ÿฌํ•œ ์—ญํ•  ๋ถ„๋‹ด์„ ๊ธฐ์–ตํ•˜๊ณ  ์ž˜ ํ™œ์šฉํ•˜๋Š”๊ฒŒ ์ค‘์š”ํ•˜๋‹ค.

๊ธˆ๊ณ ์ง€๊ธฐ์ธ reducer์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ์žˆ๋‹ค. reducer๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž!
(์ฐธ๊ณ ๋กœ ์ฐฝ๊ตฌ ์ง์›๋“ค์€ reducer์—๊ฒŒ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ๋งŒ ํ•ด์ค€๋‹ค)


1. ์Šคํ† ์–ด ์ƒ์„ฑ

import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./js/reducers/index.js";

const store = configureStore({
    reducer: rootReducer,
    devTools:
        window.__REDUX__DEVTOOLS_EXTENSION__ &&
        window.__REDUX__DEVTOOLS_EXTENSION__(),
});

configureStore๋Š” ๊ธฐ์กด๋ฌธ๋ฒ•์ธ createStore์„ ์‚ฌ์šฉํ•  ๋•Œ ์ทจ์†Œ์„ ์ด ์ƒ๊ธฐ๋ฉด์„œ deprecated ๋˜์—ˆ์œผ๋‹ˆ redux/toolkit์˜ configureStore ์‚ฌ์šฉ์„ ์ถ”์ฒœํ•œ๋‹ค๋Š” ๋ฌธ๊ตฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์•ˆ๋‚ด์— ๋”ฐ๋ผ์„œ configureStore๋กœ ๋Œ€์ฒดํ•ด์คฌ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ธฐ๋ณธ์ ์œผ๋กœ redux-thunk๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๊ณ  Redux DevTools Extension์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

combineReducers๋Š” ์—ฌ๋Ÿฌ reducer๋ฅผ ํ•œ๋ฐ ๋ชจ์€๋‹ค. ์ƒํƒœ๋Š” ๊ฐ์ฒดํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๋ฉฐ, ๊ฐ ๋ฆฌ๋“€์„œ๋Š” (state, action)์˜ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฆฌ๋•์Šค์˜ ์Šฌ๋ผ์ด์Šค ๋ฆฌ๋“€์„œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๊ธฐ์กด์˜ ์ƒํƒœ ๊ฐ์ฒด์— ํ•ฉ์ณ์ง„๋‹ค. ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด combineReducers์ด๋‹ค. ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ES6์˜ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด๋กœ ์ƒํƒœ์˜ ํ˜•ํƒœ๋ฅผ ์ •์˜ํ•œ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ์ฒด ์•ˆ์˜ ๊ฐ’๋“ค์€ ์ƒํƒœ์˜ key๋กœ ์ €์žฅ๋œ๋‹ค.


2. Reducer ์ƒ์„ฑ

// index.js

import { combineReducers } from "redux";
import login from "./loginReducer.js";

const rootReducer = combineReducers({ login });

export default rootReducer;

๋ฆฌ๋“€์„œ์˜ ํ•จ์ˆ˜ ์ด๋ฆ„์€ combineReducers์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ์ฒด์˜ ์•ˆ์— ๋“ค์–ด๊ฐ„๋‹ค. ์ฆ‰ ์ด ํ•จ์ˆ˜์˜ ์ด๋ฆ„ ์ž์ฒด๊ฐ€ state์˜ key๊ฐ€ ๋œ๋‹ค. ์ƒํƒœ์˜ ๊ฐ€์žฅ ์ƒ์œ„ ์ด๋ฆ„์ด ๋œ๋‹ค.

// loginReducer.js

import { LOGIN_USER } from "../actions/types.js"; // type์€ ๋ณ„๋„์˜ ํŒŒ์ผ์— ๋ชจ์•„๋‘”๋‹ค

const initialState = {
    loginType: "BUYER",
    typeButtonStyle: {
        buyer: true,
        seller: false,
    },
};

export default function login(state = initialState, action) {
    switch (action.type) {
		...

        case LOGIN_USER:
            return {
                ...state, // ์ƒˆ๋กœ์šด ์ •๋ณด๋กœ ๋ฎ์–ด์“ฐ๊ธฐ!
                loginType: action.loginType,
                token: action.token,
                typeButtonStyle: {
                    buyer: action.buyer,
                    seller: action.seller,
                },
            };

        default:
            return state;
    }
}

๋กœ๊ทธ์ธ ๋ฆฌ๋“€์„œ๋Š” state์™€ action์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค. ์—ฌ๊ธฐ์„œ state๋Š” ๊ตฌ state๋ฅผ ์˜๋ฏธํ•˜๊ณ  action์€ ๋ฐ”๊พธ๊ณ ์ž ํ•˜๋Š” ๋‚ด์šฉ์„ ๋‹ด๊ณ  ์žˆ๋‹ค. ์ด ๋‘˜์„ ์กฐํ•ฉํ•ด์„œ ์‹  state๋ฅผ ๋งŒ๋“ ๋‹ค. ํŒ๋งค์ž ๋ฒ„ํŠผ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•˜๊ณ  ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค ์Šคํƒ€์ผ์ด ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์„œ ์ƒํƒœ๋ฅผ ๊ตฌ์กฐํ™”ํ–ˆ๋‹ค.

์ฒ˜์Œ์— ๊ตฌ์กฐ๋ฅผ ์ž˜ ์„ค๊ณ„ํ•ด์•ผ ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ ์ž˜ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ๋‹ค.

// ์ „๊ฐœ๊ตฌ๋ฌธ ์‚ฌ์šฉ๋ฐฉ์‹

const data = {
  'id': 1,
  'name': 'Moon Hee',
  'age': 29,
}

console.log({ ...data, 'age': 30 }); // { id: 1, name: 'Moon Hee', age: 30 }

3. dispatch๋ฅผ ์ด์šฉํ•œ ์ƒํƒœ ๋ณ€๊ฒฝ

import store from "../../../store.js";

class BuyerButton {
    constructor() {
        this.button = document.createElement("button");
    }

    storeType() {
        store.dispatch({
            type: "LOGIN_USER",
            loginType: "BUYER",
            buyer: true,
            seller: false,
        });
    }

    render() {
		...

        this.button.addEventListener("click", this.storeType);

        store.subscribe(() => {
            this.button.style.backgroundColor = store.getState().login
                .typeButtonStyle.buyer
                ? "inherit"
                : "#e9e9e9";
            this.button.classList.remove(
                store.getState().login.typeButtonStyle.buyer ? "help" : "on"
            );
            this.button.classList.add(
                store.getState().login.typeButtonStyle.buyer ? "on" : "help"
            );
        });

        return this.button;
    }
}

export default BuyerButton;

dispatch๋Š” reducer๋ฅผ ํ˜ธ์ถœํ•ด์„œ state๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค. ์ „๋‹ฌํ•  ๋‚ด์šฉ์€ ์–ด๋–ค state๋ฅผ ๋ฐ”๊ฟ”์•ผํ• ์ง€ ์•Œ๋ ค์ฃผ๋Š” type๊ณผ ๋ฐ”๊พธ๊ณ  ์‹ถ์€ ๋‚ด์šฉ์„ ๊ฐ์ฒด์— ๋‹ด์•„์„œ ๋ณด๋‚ธ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” useDispatch๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๋ฐ”๋‹๋ผ์—์„œ๋Š” store.dispatch() ํ˜•์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

subscribe๋Š” ์Šคํ† ์–ด์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์ธ์ž์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๊ตฌ๋งค์ž ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ํŒ๋งค์ž ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ dispatch๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์ด๊ฒƒ์ด ์Šคํ† ์–ด์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด ๊ทธ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉ์‹œ์ผœ์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.


์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์™€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„˜๋‚˜๋“ค๋ฉด์„œ ์ฝ”๋”ฉํ–ˆ๊ณ  ๋ Œ๋”๋ง ์‹œ์ ์„ ๋”ฐ์ ธ์„œ setTimeout๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค. Redux๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์— ์ง์ ‘ ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ง„๋‹ค. ๋กœ๊ทธ์ธ ํƒ€์ž… ์ปดํฌ๋„ŒํŠธ์—์„œ 33์ค„์ด ์ค„์–ด๋“ค์—ˆ๊ณ  ๊ทธ๋ƒฅ ์งง์•„์ง„๊ฒŒ ์•„๋‹ˆ๋ผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์ฃผ์ธ์—๊ฒŒ ์ฝ”๋“œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์–ด์„œ ๋งค์šฐ๋งค์šฐ ์ข‹์•„์กŒ๋‹ค.

profile
์ž๊ณ  ์ผ์–ด๋‚˜๋ฉด ํ•ด๊ฒฐ๋˜๋Š”๊ฒŒ ๋” ๋งŽ์€ ๋“ฏ ๊ทธ๋Ÿผ ์ž˜๊นŒ

0๊ฐœ์˜ ๋Œ“๊ธ€