๐Ÿ“• ์žฌ๋ฏธ์žˆ๋Š” Redux(0)

16085 ๋‹จ์–ด frontendfrontend

์‚ฌ์‹ค ๋ฆฌ๋•์Šค๋Š” ์žฌ๋ฏธ๊ฐ€ ์—†๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋ ต๊ธฐ๊นŒ์ง€ ํ•˜๋‹ค. ๋ฆฌ๋•์Šค์˜ ๋‹จ์  ์ค‘ ๋†’์€ ๋Ÿฌ๋‹ ์ปค๋ธŒ๊ฐ€ ์žˆ๋Š” ๊ฑธ ๋ณด๋ฉด ๋น„๋‹จ ๋‚˜๋งŒ ๊ทธ๋Ÿฐ ๊ฑด ์•„๋‹Œ ๊ฒƒ ๊ฐ™๋‹ค.

ํ•˜์ง€๋งŒ ๋ฆฌ๋•์Šค๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์—์„œ ์ƒํƒœ๊ด€๋ฆฌ๋ž€ ๋” ์žฌ๋ฏธ์—†๊ณ  ๊ฐ€๋” ํ™”๊ฐ€ ๋‚˜๊ธฐ๋„ ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ ํ”„๋ก ํŠธ์—”๋“œ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ ์ค‘ ํ•˜๋‚˜์ธ ์ƒํƒœ ๊ด€๋ฆฌ์— ๋Œ€ํ•ด ์กฐ๊ธˆ์ด๋ผ๋„ ์ž˜ ํ•ด๋‚ด๊ธฐ ์œ„ํ•ด ๋ฆฌ๋•์Šค๋ฅผ ๋ฐฐ์›Œ๋ณด์ž.

Redux?

ํŽ˜์ด์Šค๋ถ(ํ˜„ ๋ฉ”ํƒ€)์€ ์ž์‹ ์˜ ๊ณ ์งˆ์ ์ธ ๋ฌธ์ œ์ ์„ ๊ณ ์น˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด ํŒจํ„ด Flux๋ฅผ ๋ฐœํ‘œํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Flux์™€ ์ฃผ์–ด์ง„ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ธ reduce์˜ ๊ฐœ๋…์„ ๊ฒฐํ•ฉํ•ด Redux๋ผ๋Š” ๋„๊ตฌ๊ฐ€ ์„ธ์ƒ์— ๋‚˜ํƒ€๋‚ฌ๋‹ค.

Redux์˜ ๋™์ž‘์€ ํฌ๊ฒŒ 4๊ฐ€์ง€ ์š”์†Œ์˜ ํ˜‘์—…์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. Action creator
  2. Dispatcher
  3. Store
  4. Rendering function

์•ก์…˜์— ๋”ฐ๋ผ ๋””์ŠคํŒจ์ณ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๋ฆฌ๋“€์„œ์—์„œ state๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ž„์˜์˜ ๋ Œ๋” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ  ์Šคํ† ์–ด๊ฐ€ ๊ทธ ํ•จ์ˆ˜๋ฅผ ๊ตฌ๋…ํ•œ๋‹ค๋ฉด ํ˜ธ์ถœํ•˜๋Š” ํ˜•์‹์ด๋‹ค.

๐Ÿ”จ ์‹ค์Šต

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="./counter.js" defer></script>
    <title>Document</title>
  </head>
  <body>
    <span class="number">0</span>
    <button class="plus">+</button>
    <button class="minus">-</button>
    <button class="unsubscribe">Unsubscribe</button>
  </body>
</html>

๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ˆซ์ž๊ฐ€ ๋ณ€ํ•˜๋Š” ์นด์šดํ„ฐ๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•œ๋‹ค. Store์˜ State์— ๋”ฐ๋ผ ๊ฐ’์ด ๋ณ€ํ•˜๊ณ  Unsubscribe ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ตฌ๋…์ด ํ•ด์ง€๋œ๋‹ค.

import { createStore } from "redux";

const PLUS = "PLUS";
const MINUS = "MINUS";

const plus = () => ({ type: PLUS });
const minus = () => ({ type: MINUS });

const initialState = 0;

function counterReducer(state = initialState, action) {
  console.log(action);

  switch (action.type) {
    case PLUS:
      return state + 1;
    case MINUS:
      return state - 1;
    default:
      return state;
  }
}

const store = createStore(counterReducer);

๊ฐ๊ฐ type์œผ๋กœ PLUS์™€ MINUS๋ฅผ ๊ฐ–๋Š” ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ˆซ์ž์˜ ์ดˆ๊ธฐ๊ฐ’์ธ initialState, ์•ก์…˜์— ๋”ฐ๋ผ State๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” reducer๋ฅผ ๋งŒ๋“ ๋‹ค.

store๋Š” ๋ฆฌ๋•์Šค ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ dispatcher๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

function init() {
  const number = document.querySelector(".number");
  const plusBtn = document.querySelector(".plus");
  const minusBtn = document.querySelector(".minus");
  const unsubscribeBtn = document.querySelector(".unsubscribe");

  const render = () => {
    const state = store.getState();

    number.innerText = state;
  };

  const unsubscribe = store.subscribe(render);
  
  plusBtn.addEventListener("click", () => store.dispatch(plus()));
  minusBtn.addEventListener("click", () => store.dispatch(minus()));
  unsubscribeBtn.addEventListener("click", () => unsubscribe());
}

init();

๋ฒ„ํŠผ์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋“ค์„ ๋“ฑ๋กํ•˜๊ณ  store๊ฐ€ render ํ•จ์ˆ˜๋ฅผ ๊ตฌ๋…ํ•˜๊ฒŒ ํ•œ๋‹ค. store๋Š” state๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค render ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  subscribe ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋กœ unsubscribe ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š”๋ฐ ์ด๊ฒƒ์„ ์ด์šฉํ•ด ๊ตฌ๋…์„ ํ•ด์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ˜ช ํ›„๊ธฐ

๋ฆฌ๋•์Šค ํŒจํ‚ค์ง€ ๋‚ด๋ถ€์˜ module import๊ฐ€ ๋ณต์žกํ•ด์„œ parcel ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•ด ์ž‘๋™์‹œ์ผฐ๋‹ค.

๊ฐ„๋‹จํ•œ ์นด์šดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋ฆฌ๋•์Šค์˜ ์ผ๋ถ€ ๊ธฐ๋Šฅ๋งŒ์„ ์‚ฌ์šฉํ–ˆ์„ ๋ฟ์ธ๋ฐ ์ฝ”๋“œ์˜ ์–‘์ด ์ƒ๋‹นํ•˜๋‹ค.

๋ฆฌ๋•์Šค ๊ฐœ๋ฐœ์ž์ธ Dan abromove๋Š” You might not need redux๋ผ๋Š” ๊ธ€์„ ์˜ฌ๋ ธ๋‹ค. ๋„๊ตฌ๋ฅผ ๋„์ž…ํ•˜๊ธฐ ์ด์ „ ์•ฑ์˜ ๊ทœ๋ชจ๋‚˜ ๊ธฐ๋Šฅ์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ์„ ํƒํ•˜๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ