React ์ƒํƒœ ๊ด€๋ฆฌ - Redux ๐Ÿ”

forhreverยท2023๋…„ 2์›” 24์ผ
0

๐Ÿ“ข Redux

Javascipt ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. Redux๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด store๋ผ๋Š” ๋ฐ์ดํ„ฐ ๊ณต๊ฐ„์„ ๋งŒ๋“  ํ›„ ํ•ด๋‹น ๊ณต๊ฐ„ ์•ˆ์—์„œ ๋ฐ์ดํ„ฐ์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. Redux์—๋Š” store, action, reducer๋ผ๋Š” ์„ธ๊ฐ€์ง€ ๊ฐœ๋…์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

Redux ์„ค์น˜ ๋ฐฉ๋ฒ•

npm install redux
npm install react-redux
npm install redux-actions
npm install redux-devtools-extenstion 
npm install immer

Redux ์ƒํƒœ ๊ด€๋ฆฌ ์ˆœ์„œ
1. ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋ณ€๊ฒฝ๋  ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด Aciton ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
2. ์ด Action ๊ฐ์ฒด๋Š” Dispatch ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
3. Dispatch ํ•จ์ˆ˜๋Š” Action ๊ฐ์ฒด๋ฅผ Reducer ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ด์ค๋‹ˆ๋‹ค.
4. Reducer ํ•จ์ˆ˜๋Š” Action ๊ฐ์ฒด์˜ ๊ฐ’์„ ํ™•์ธํ•˜๊ณ , ๊ทธ ๊ฐ’์— ๋”ฐ๋ผ ์ „์—ญ ์ƒํƒœ ์ €์žฅ์†Œ store์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
5. ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด, React๋Š” ํ™”๋ฉด์„ ๋‹ค์‹œ ๋ Œ๋”๋ง ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก Store

์ƒํƒœ๊ฐ€ ๊ด€๋ฆฌ๋˜๋Š” ์˜ค์ง ํ•˜๋‚˜๋ฟ์ธ ์ €์žฅ์†Œ์˜ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

import { createStore } from 'redux';
const store = createStore(rootReducer);

๐Ÿ’ก Reducer

Dispatch์—๊ฒŒ์„œ ์ „๋‹ฌ๋ฐ›์€ Action ๊ฐ์ฒด์˜ type ๊ฐ’์— ๋”ฐ๋ผ์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. Reducer๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ์š”์ธ์œผ๋กœ ์ธํ•ด ๊ธฐ๋Œ€ํ•œ ๊ฐ’์ด ์•„๋‹Œ ์—‰๋šฑํ•œ ๊ฐ’์œผ๋กœ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ์ผ์ด ์—†์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

const count = 1

// Reducer๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์—๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ธ์ž๋กœ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
const counterReducer = (state = count, action) => {

  // Action ๊ฐ์ฒด์˜ type ๊ฐ’์— ๋”ฐ๋ผ ๋ถ„๊ธฐํ•˜๋Š” switch ์กฐ๊ฑด๋ฌธ์ž…๋‹ˆ๋‹ค.
  switch (action.type) {

    //action === 'INCREASE'์ผ ๊ฒฝ์šฐ
    case 'INCREASE':
			return state + 1

    // action === 'DECREASE'์ผ ๊ฒฝ์šฐ
    case 'DECREASE':
			return state - 1

    // action === 'SET_NUMBER'์ผ ๊ฒฝ์šฐ
    case 'SET_NUMBER':
			return action.payload

    // ํ•ด๋‹น ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์—†์„ ๋• ๊ธฐ์กด ์ƒํƒœ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ด
    default:
      return state;
	}
}
// Reducer๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ’์ด ์ƒˆ๋กœ์šด ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

combineReducers ๋ฉ”์„œ๋“œ

์—ฌ๋Ÿฌ๊ฐœ์˜ reducer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ. Redux์˜ combineReducers ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•˜๋‚˜์˜ Reducer๋กœ ํ•ฉ์ณ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  counterReducer,
  anyReducer,
  ...
});

๐Ÿ’ก Action

์–ด๋–ค ์•ก์…˜์„ ์ทจํ•  ๊ฒƒ์ธ์ง€ ์ •์˜ํ•ด ๋†“์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

  • type์€ ํ•„์ˆ˜๋กœ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด๋‹น Action ๊ฐ์ฒด๊ฐ€ ์–ด๋–ค ๋™์ž‘์„ ํ•˜๋Š” ์ง€ ๋ช…์‹œํ•ด์ค€๋‹ค.
  • ๋Œ€๋ฌธ์ž์™€ Snake Case๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„์š”์— ๋”ฐ๋ผ payload๋ฅผ ์ž‘์„ฑํ•ด ๊ตฌ์ฒด์ ์ธ ๊ฐ’์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
// payload๊ฐ€ ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ
const increase = () => {
  return {
    type: 'INCREASE'
  }
}

// payload๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ
const setNumber = (num) => {
  return {
    type: 'SET_NUMBER',
    payload: num
  }
}

๐Ÿ’ก Dispatch

Reducer๋กœ Action์„ ์ „๋‹ฌํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. Dispatch์˜ ์ „๋‹ฌ์ธ์ž๋กœ Action ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

  • Action ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ๋ฐ›์€ Dispatch ํ•จ์ˆ˜๋Š” Reducer๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
// Action ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );

// ์•ก์…˜ ์ƒ์„ฑ์ž(Action Creator)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
dispatch( increase() );
dispatch( setNumber(5) );

๐Ÿ“ข React-redux

React์—์„œ Redux๋ฅผ ์‚ฌ์šฉํ•ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ Redux ๋ฟ๋งŒ์•„๋‹ˆ๋ผ React์™€ Redux๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€๋กœ ์„ค์น˜ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Redux Hooks

React-Redux์—์„œ Redux๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Hooks ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ค‘์—์„œ ํฌ๊ฒŒ useSelector(), useDispatch() ์ด ๋‘ ๊ฐ€์ง€์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

useDispatch()

Action ๊ฐ์ฒด๋ฅผ Reducer๋กœ ์ „๋‹ฌํ•ด ์ฃผ๋Š” Dispatch ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

import { useDispatch } from 'react-redux'

const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2

dispatch( setNumber(5) )
console.log(counter) // 5

useSelector()

์ปดํฌ๋„ŒํŠธ์™€ state๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ Redux์˜ state์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

// Redux Hooks ๋ฉ”์„œ๋“œ๋Š” 'redux'๊ฐ€ ์•„๋‹ˆ๋ผ 'react-redux'์—์„œ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
import { useSelector } from 'react-redux'
const counter = useSelector(state => state)
console.log(counter) // 1

๐Ÿ“ข Redux-actions

redux-actions ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณต๋˜๋Š” createAction๊ณผ handleActions ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋ฉด redux์—์„œ ๋ณด๋‹ค ์‰ฝ๊ฒŒ action๋“ค์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

createAction

์ด ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋ฉด action ์ƒ์„ฑ์„ ์ž๋™ํ™” ํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. createAction ํ•จ์ˆ˜์˜ ์ธ์ž๊ฐ’์œผ๋กœ type ๋‚ด์šฉ์„ ์ „๋‹ฌํ•ด์ฃผ๋ฉด ์ „๋‹ฌ๋ฐ›์€ type์„ ๊ฐ€์ง„ action ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ๋˜ํ•œ createAction ํ•จ์ˆ˜๋กœ ๋งŒ๋“  action ์ƒ์„ฑ ํ•จ์ˆ˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ’์„ action์˜ payload ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค.

handleActions

reducer์—์„œ action์˜ type์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ switch๋ฌธ์„ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ switch๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ scope๊ฐ€ reducer ํ•จ์ˆ˜๋กœ ์„ค์ •๋œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋กœ ๋‹ค๋ฅธ case์—์„œ let์ด๋‚˜ const๋ฅผ ํ†ตํ•ด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๊ฐ™์€ ์ด๋ฆ„์ด ์ค‘์ฒฉ๋  ์‹œ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ handleActions ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { createAction, handleActions } from 'redux-actions';

const SAMPLE_ACTION = 'auth/SAMPLE_ACTION';

export const sampleAction = createAction(SAMPLE_ACTION);

const initialState = {};

const auth = handleActions(
    {
        [SAMPLE_ACTION] : (state, action) => state,
    },
    initialState,
);

export default auth;

๐Ÿ“ข immer

immer๋Š” React์—์„œ ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. React ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•œ ์ผ์ž…๋‹ˆ๋‹ค. ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค์ง€ ์•Š์œผ๋ฉด ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ๊ฐ’์ด ์ƒˆ๋กœ์›Œ์ ธ๋„ ๋ฐ”๋€ ๊ฒƒ์„ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

  • React์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ๋‚ด๋ ค๋ฐ›๋Š” props๋‚˜ ๋‚ด๋ถ€ ์ƒํƒœ์ธ state๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋žœ๋”๋ง ํ•˜๋Š” ๋ฆฌ๋žœ๋”๋ง ๊ณผ์ •์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  • React๋Š” ์ด props์™€ state์˜ ๋ณ€๊ฒฝ์„ ๋ถˆ๋ณ€์„ฑ์„ ์ด์šฉํ•ด์„œ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค๋Š” ์ ์„ ์ด์šฉํ•ด ๋‹จ์ˆœํžˆ ์ฐธ์กฐ๋งŒ ๋น„๊ตํ•˜๋Š” ์–•์€ ๋น„๊ต๋ฅผ ํ†ตํ•ด์„œ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ JavaScript์—์„œ ์ฐธ์กฐ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ์ธ ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ ํž™ ์˜์—ญ์— ์ €์žฅ๋˜์–ด ๋‚ด๋ถ€ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•ด๋„ ๊ฐ™์€ ์ฐธ์กฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ๋งŒ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด React์—์„œ๋Š” ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ธ์‹ํ•˜์—ฌ ๋ฆฌ๋žœ๋”๋ง์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฆฌ๋žœ๋”๋ง์„ ์ผ์œผํ‚ค๊ธฐ ์œ„ํ•ด์„œ๋Š” React์— ์ด์ „์˜ ์ฐธ์กฐ์™€ ๋‹ค๋ฅธ ์ฐธ์กฐ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ์•Œ๋ ค์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ข Redux์˜ ์„ธ ๊ฐ€์ง€ ์›์น™

1. Single source of truth

๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๊ณณ์—์„œ ๊ฐ€์ง€๊ณ  ์™€์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์ฆ‰, Redux์—๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” Store๋ผ๋Š” ๋‹จ ํ•˜๋‚˜๋ฟ์ธ ๊ณต๊ฐ„์ด ์žˆ์Œ๊ณผ ์—ฐ๊ฒฐ์ด ๋˜๋Š” ์›์น™์ž…๋‹ˆ๋‹ค.

2. State is read-only

์ƒํƒœ๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด๋ผ๋Š” ๋œป์œผ๋กœ, React์—์„œ ์ƒํƒœ๊ฐฑ์‹ ํ•จ์ˆ˜๋กœ๋งŒ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ, Redux์˜ ์ƒํƒœ๋„ ์ง์ ‘ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, Action ๊ฐ์ฒด๊ฐ€ ์žˆ์–ด์•ผ๋งŒ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ๊ณผ ์—ฐ๊ฒฐ๋˜๋Š” ์›์น™์ž…๋‹ˆ๋‹ค.

3. Changes are made with pure functions

๋ณ€๊ฒฝ์€ ์ˆœ์ˆ˜ํ•จ์ˆ˜๋กœ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋œป์œผ๋กœ, ์ƒํƒœ๊ฐ€ ์—‰๋šฑํ•œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ์ผ์ด ์—†๋„๋ก ์ˆœ์ˆ˜ํ•จ์ˆ˜๋กœ ์ž‘์„ฑ๋˜์–ด์•ผํ•˜๋Š” Reducer์™€ ์—ฐ๊ฒฐ๋˜๋Š” ์›์น™์ž…๋‹ˆ๋‹ค.


์ฐธ๊ณ ํ•œ ์ž๋ฃŒ ์ถœ์ฒ˜
https://bitkunst.tistory.com/entry/React-react-redux
https://bitkunst.tistory.com/entry/Redux-redux-actions

profile
๊ฐœ๋ฐœ์ž ์„ฑ์žฅ ๊ณ„๋‹จ ์˜ฌ๋ผ๊ฐ€๊ธฐ

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