๐Ÿฒ Redux์™€ TypeScript

๋ฐ•์ƒ์€ยท2022๋…„ 7์›” 2์ผ
0
post-thumbnail

Redux + TypeScript์— ๋Œ€ํ•œ ํฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

๐Ÿค” Redux ์‚ฌ์šฉ ์ด์œ 

ํ”„๋กœ์ ํŠธ์˜ ์ „์ฒด์ ์ธ ๋ฐ์ดํ„ฐ(์ƒํƒœ)๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ณ  ํ๋ฆ„์— ๋งž๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
React.js๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๋ณด๋ฉด ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๊ฐ๊ฐ์˜ state๋ฅผ ์ด์šฉํ•ด์„œ ๊ด€๋ฆฌํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๋ฉด ํŽธํ•˜๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋“ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๋ฌผ๋ก  Redux๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  React.js๋งŒ์œผ๋กœ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ƒํƒœ๋ฅผ ์ •์˜ํ•˜๊ณ  props๋ฅผ ์ด์šฉํ•ด์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ณ„์† ์ „๋‹ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ๊ฒฝํ—˜ํ•ด๋ณด์‹œ๋ฉด ์•Œ๊ฒŒ ๋˜๊ฒ ์ง€๋งŒ ๊ฐ€๋…์„ฑ์ด ๋งค์šฐ ์•ˆ์ข‹์•„์ง€๊ณ  ํ•˜๋‚˜์˜ ์ˆ˜์ •์— ์˜ํ•œ ๋ณ€๊ฒฝํ•ด์•ผํ•  ์ฝ”๋“œ๊ฐ€ ์ •๋ง ๋งŽ์•„์ง‘๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ถˆํŽธํ•จ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋Œ€๋ถ€๋ถ„ Redux๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Redux๋Š” ํ•˜๋‚˜์˜ ์ƒํƒœ๋ฅผ ๊ฐ–๋Š” ํฐ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ์ฝ”๋“œ๊ฐ€ ๊ผฌ์ด์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ FluxํŒจํ„ด์„ ์ด์šฉํ•ด์•ผ๋งŒ ๊ทธ ๊ฐ์ฒด๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘๊ฐ„ ์ •๋ฆฌ๋ฅผ ํ•˜์ž๋ฉด Redux๋Š” ํ•˜๋‚˜์˜ ํฐ ์ƒํƒœ๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด์ธ store๋ฅผ ๊ฐ–๊ณ  ๊ทธ store๋ฅผ ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ props๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ ค์ฃผ๋Š” ๊ณผ์ •์ด ํ•„์š”์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ React.js์—์„œ๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” store๋ฅผ ์ธ์ง€ํ•˜๊ณ  ๊ตฌ๋…ํ•จ์œผ๋กœ์จ store๊ฐ€ ๋ณ€๊ฒฝ๋จ์— ์˜ํ•ด์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋žœ๋”๋ง์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„์„ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด์„œ FluxํŒจํ„ด์„ ์ด์šฉํ•ด์•ผ๋งŒ store๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋ฐ์ดํ„ฐ์˜ ์‹ ๋ขฐ์„ฑ๋„ ๋†’์•„์ง‘๋‹ˆ๋‹ค.

๐Ÿง Flux ํŒจํ„ด

  • ์ฃผ์š” ๊ฐœ๋…๋“ค
    1. store: ์ „์ฒด์ ์ธ ๋ฐ์ดํ„ฐ(์ƒํƒœ)๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•˜๋‚˜์˜ ํฐ ๊ฐ์ฒด
    2. action: ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ type๊ณผ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•œ payload๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด
    3. dispatch: ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด action๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜
    4. reducer: ์ƒํƒœ์— ๋Œ€ํ•œ ์ •์˜์™€ ์ƒํƒœ์˜ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ๊ฐ–๋Š” ํ•จ์ˆ˜

๋ฐ์ดํ„ฐ๊ฐ€ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ๋งŒ ํ๋ฅด๊ฒŒ ๋ณด์žฅ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์•„ํ‚คํ…์ฒ˜์ž…๋‹ˆ๋‹ค.
action์„ dispatchํ•ด์„œ reducer๋กœ ๋ณด๋‚ธ ํ›„ ์ •์˜๋œ ์ฒ˜๋ฆฌ๋ฅผ ์™„๋ฃŒํ•˜๊ณ  ์ƒˆ๋กœ์šด state, store๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

โœจ ์˜ˆ์‹œ

Redux๋งŒ์„ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// legacy_createStore๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” Redux์—์„œ ์ด์ œ๋Š” redux-toolkit์„ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ
import {
  legacy_createStore as createStore,
  combineReducers,
  applyMiddleware,
} from "redux";

// type ( as const๋ฅผ ์ด์šฉํ•ด์„œ ๋ถˆ๋ณ€์ž„์„ ์ •์˜ )
const ADD_USER = "ADD_USER" as const;
const ADD_POST = "ADD_POST" as const;

// action ( ์•ก์…˜์„ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜... ์ง์ ‘์ ์œผ๋กœ ์•ก์…˜์„ ์ „๋‹ฌํ•ด๋„ ๋˜์ง€๋งŒ ์•ก์…˜์ด ๋งŽ์•„์ง€๋ฉด ํ—ท๊ฐˆ๋ ค์„œ ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ ์ •์˜ํ•จ )
const addUser = () => ({ type: ADD_USER });
const addPost = (payload: number) => ({ type: ADD_POST, payload });
// ์•ก์…˜์˜ ํƒ€์ž… ( reducer์—์„œ ์‚ฌ์šฉ )
type UserAction = ReturnType<typeof addUser>;
type PostAction = ReturnType<typeof addPost>;

// reducer
// ์œ ์ € ๋ฆฌ๋“€์„œ ์ •์˜
const userInitialState = {
  users: 333,
};
type UserStateType = typeof userInitialState;
const userReducer = (
  state: UserStateType = userInitialState,
  action: UserAction
): UserStateType => {
  switch (action.type) {
    case ADD_USER:
      return {
        ...state,
        users: state.users + 1,
      };

    default:
      return state;
  }
};
// ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ๋“€์„œ ์ •์˜
const PostInitialState = {
  posts: 5555,
};
type PostStateType = typeof PostInitialState;
const postReducer = (
  state: PostStateType = PostInitialState,
  action: PostAction
): PostStateType => {
  switch (action.type) {
    case ADD_POST:
      return {
        ...state,
        posts: state.posts + action.payload,
      };

    default:
      return state;
  }
};
// ๋ฆฌ๋“€์„œ ํ•ฉ์นจ
const rootReducer = combineReducers({
  user: userReducer,
  post: postReducer,
});

// middleware ( ์ง์ ‘ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ ๋ฏธ๋“ค์›จ์–ด... action์ด reducer๋กœ ์ „๋‹ฌ๋˜๊ธฐ ์ „์— ์‹คํ–‰ )
const logger = (store: any) => (next: any) => (action: any) => {
  // ์›ํ•˜๋Š” ์ž‘์—… ( action์ด reducer๋กœ ์ „๋‹ฌ๋˜๊ธฐ ์ „ )
  console.log("middleware >> ", action);

  // next()๋ฅผ ์ด์šฉํ•ด์„œ action์ด reducer๋กœ ์ „๋‹ฌ๋จ
  return next(action);
};

// store ์ƒ์„ฑ ( getState, subscribe, getState ๋“ฑ์ด ๋“ค์–ด์žˆ์Œ )
const store = createStore(rootReducer, applyMiddleware(logger));

console.log(store.getState());
store.dispatch(addUser());
store.dispatch(addPost(1111));
console.log(store.getState());

/**
 * { user: { users: 333 }, post: { posts: 5555 } }
 * middleware >>  { type: 'ADD_USER' }
 * middleware >>  { type: 'ADD_POST', payload: 1111 }
 * { user: { users: 334 }, post: { posts: 6666 } }
 */

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