[React.js] Redux (2)


๐Ÿš€ย redux ์ž‘๋™๋ฐฉ์‹

  • ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ(๋ฐ์ดํ„ฐ)๋ฅผ Store๋ผ๋Š” ๋‹จ์ผ ์œ„์น˜์— ์ €์žฅ.ย ํ”„๋ŸฐํŠธ์—”๋“œ์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์ €์žฅ
  • 3๊ฐ€์ง€ ์ฃผ์š” ๋ถ€๋ถ„
    • Store - ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ
    • Reducer - ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€, ์—…๋ฐ์ดํŠธ ๋ฐ ์‚ญ์ œํ•˜๋Š” ๊ธฐ๋Šฅ(์‚ฌ์šฉ ๋ฐฉ๋ฒ•) โ€ข
    • Actions - ์ˆ˜ํ–‰ํ•  ์ž‘์—…(๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€)์„ ์ •์˜
  • Reducer ๊ธฐ๋Šฅ์„ ํ†ตํ•ด์„œ๋งŒ Store ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค..
  • ํ• ์ผ ๋ชฉ๋ก ๋งŒ๋“ค๊ธฐ
    • Action - ADD_TASK
    • Reducer - perform how to add task in the store

๐Ÿ“Œย Redux ๊ตฌํ˜„์„ ์œ„ํ•œ 4๋‹จ๊ณ„:

  • Designing the store - Store ๊ฐ์ฒด์˜ ๋ชจ์Šต
  • List actions - ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ˆ˜ํ–‰
  • ๋ฆฌ๋“€์„œ ๋งŒ๋“ค๊ธฐ - ํ•ด๋‹น ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•˜๋Š” ๊ธฐ๋Šฅ
  • ๋ฆฌ๋•์Šค ์Šคํ† ์–ด ์ƒ์„ฑ

๐Ÿ’ปCreating Reducer function:

  • ๊ฐ์†๊ธฐ๋Š” ๋‘ ๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.ย ์ฒซ ๋ฒˆ์งธ๋Š” ์ดˆ๊ธฐ ๋˜๋Š” ํ˜„์žฌ ์ƒํƒœ์ด๊ณ  ๋‘ ๋ฒˆ์งธ๋Š” ์ž‘์—… ๊ฐœ์ฒด
  • ์ด ํ•จ์ˆ˜ ๋‚ด์—์„œ If..else๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ Switch ์ผ€์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—… ์œ ํ˜•์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
let id = 0;
export default function reducer(state = [], action) {
  switch (action.type) {
    case ADD_TASK:
      return [
        ...state,
        {
          id: ++id,
          task: action.payload.task,
          completed: false,
        },
      ];
    case REMOVE_TASK:
      return state.filter((task) => task.id !== action.payload.id);
    case TASK_COMPLETED:
      return state.map((task) =>
        task.id === action.payload.id
          ? {
              ...task,
              completed: true,
            }
          : task
      );
    default:
      return state;
  }
}

๐Ÿ“œย redux ์Šคํ† ์–ด ๊ตฌ์„ฑ

  • ๋ฆฌ๋•์Šค ์Šคํ† ์–ด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ๋ฆฌ๋•์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— createStore๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๊ณ  ๋ฃจํŠธ ๋ฆฌ๋“€์„œ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋Œ.
import { legacy_createStore as createStore } from "redux";
import reducer from "./tasks";
const store = createStore(reducer);
export default store;

๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย  Store์—์„œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

  • ์–ด๋–ค ์•ก์…˜์„ ๋ฐœ์†กํ•˜๋ ค๋ฉด store.dispatch ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ  type ์†์„ฑ(์•ก์…˜ ์ด๋ฆ„)๊ณผ ํŽ˜์ด๋กœ๋“œ ์†์„ฑ(์•ก์…˜๊ณผ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ)์„ ๊ฐ€์ง„ ์•ก์…˜ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•ด์•ผ ๋Œ.
store.dispatch({ type: "ADD_TASK", payload: { task: "Add new task" } });

๐Ÿ””๊ตฌ๋… ๋ฐ ํƒˆํ‡ด ๋ฐฉ๋ฒ•

  • YouTube์—์„œ ๊ตฌ๋… ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•จ์— ๋”ฐ๋ผ store.subscribe ๋ฉ”์„œ๋“œ๋Š” ์Šคํ† ์–ด ๊ฐœ์ฒด์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ๋ฐ์—๋„ ์‚ฌ์šฉ
store.subscribe(() => {
  console.log("Updated", store.getState());
});
  • ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” redux ์Šคํ† ์–ด์˜ ๋ชจ๋“  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์—์„œ ์‹คํ–‰.
  • ์ด์ œ ์ด ๊ตฌ๋… ๋ฐฉ๋ฒ•์„ ์ค‘์ง€ํ•˜๋ ค๋ฉด ๊ตฌ๋… ์ทจ์†Œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•จ.
const unsubscribe = store.subscribe(() => {
  console.log("Updated", store.getState());
});
unsubscribe();

๐Ÿš€redux-devTools ๊ตฌ์„ฑ ๋ฐฉ๋ฒ•

npm i redux-devtools-extension ๋˜๋Š” yarn add redux-devtools-extension
  • configureStore ํŒŒ์ผ์—์„œ ์ดย ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ ํ•˜๊ณ  ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ devToolsEnhancer๋ฅผ ๊ฐ€์ ธ์˜ด.
import { legacy_createStore as createStore } from "redux";
import { devToolsEnhancer } from "redux-devtools-extension";
import reducer from "./tasks";

const store = createStore(reducer, devToolsEnhancer({ trace: true }));

export default store;
  • ๋˜ํ•œ ์ด ํ™•์žฅ์œผ๋กœ ์ถ”์ ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด ํ™•์žฅ์—์„œ ๋กœ๊ทธ ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ค๊ณ  ๋‚ด๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ์Œ.