๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Redux

๋ฆฌ๋•์Šค ์ž‘์—…ํ™˜๊ฒฝ ์„ค์ • ๋ฐ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

๋ฆฌ๋•์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด ์„ค์น˜ํ•ด์•ผํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๊ณผ ๋ฆฌ๋•์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์•Œ์•„๋ณด์ž

 

 

๐ŸŒŒ  ์ž‘์—… ํ™˜๊ฒฝ ์„ค์ • 

๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ทธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•œ ์ดํ›„ 

 

$ yarn add redux react-redux

 

yarn ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ๋•์Šค์™€ react-redux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•œ๋‹ค 

 

 

 

 

 

๐ŸŽจ ๋””์ž์ธํŒจํ„ด

 

๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฆฌ๋•์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์€ Presentational and Container Component Pattern ์ด๋‹ค

 

Container ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋•์Šค์™€ ์—ฐ๋™ํ•˜์—ฌ ๋ฆฌ๋•์Šค๋กœ๋ถ€ํ„ฐ ์ƒํƒœ๋ฅผ ๋ฐ›์•„ ์˜ค๊ธฐ๋„ ํ•˜๊ณ  ์Šคํ† ์–ด์— ์•ก์…˜์„ ๋””์ŠคํŒจ์น˜ ํ•˜๊ธฐ๋„

ํ•œ๋‹ค

Presentational ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๊ณ , ๊ทธ์ € props๋ฅผ ๋ฐ›์•„์™€์„œ ํ™”๋ฉด์— UI๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋Š”

์ปดํฌ๋„ŒํŠธ์ด๋‹ค

 

๋””์ž์ธ ํŒจํ„ด์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋”ฐ๋กœ ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑํ•˜๋ฉฐ ์•Œ์•„๋ณด์ž

 

 

๐Ÿ’ป ๋ฆฌ๋•์Šค ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ 

 

์•ก์…˜ํƒ€์ž…, ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜, ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜๋ฅผ ๊ธฐ๋Šฅ๋ณ„๋กœ ํŒŒ์ผ ํ•˜๋‚˜์— ๋ชฐ์•„์„œ ๋‹ค ์ž‘์„ฑํ•˜๋Š” ์ด ๋ฐฉ์‹์„ Ducks ํŒจํ„ด์ด๋ผ ๋ถ€๋ฅธ๋‹ค. 

 

 

์•ก์…˜ํƒ€์ž… ์ •์˜ 

 

 

const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';

 

 

์•ก์…˜ํƒ€์ž…์€ ๋Œ€๋ฌธ์ž๋กœ ์ •์˜ํ•œ๋‹ค. ๋ฌธ์ž์—ด์˜ ๋‚ด์šฉ์€ '๋ชจ๋“ˆ ์ด๋ฆ„/์•ก์…˜ ์ด๋ฆ„'์˜ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•œ๋‹ค !

๋ฌธ์ž์—ด ์•ˆ์— ๋ชจ๋“ˆ ์ด๋ฆ„์„ ๋„ฃ์Œ์œผ๋กœ์จ, ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์กŒ์„ ๋•Œ ์•ก์…˜์˜ ์ด๋ฆ„์ด ์ถฉ๋Œ๋˜์ง€ ์•Š๊ฒŒ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค 

 

 

์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ

 

export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });

 

 

export ํ‚ค์›Œ๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ด์œ ๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋กํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค

 

 

initialState ์ƒ์„ฑํ•˜๊ธฐ 

 

const initialState = {
  number: 0,
};

 

initialState๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฆฌ๋“€์„œ์—์„œ ์ด๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์ดˆ๊ธฐ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค

 

 

๋ฆฌ๋“€์„œ ์ƒ์„ฑํ•˜๊ธฐ 

 

 

function counter(state = initialState, action) {
  switch (action.type) {
    case INCREASE:
      return {
        number: state.number + 1,
      };
    case DECREASE:
      return {
        number: state.number - 1,
      };

    default:
      return state;
  }
}

export default counter;

 

 

state๋Š” initialState๋ฅผ ๋„ฃ์–ด ์ฃผ์–ด์„œ number ๊ฐ’์„ ์„ค์ •ํ•ด ์ฃผ์—ˆ๊ณ , ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜์—๋Š” ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ export default ํ‚ค์›Œ๋“œ๋กœ ํ•จ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ด ์ฃผ์—ˆ๋‹ค.

 

 

๋ฃจํŠธ ๋ฆฌ๋“€์„œ ๋งŒ๋“ค๊ธฐ 

module ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— index.js ํŒŒ์ผ์„ ๋งŒ๋“  ํ›„์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค 

 

 

import { combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';

const rootReducer = combineReducers({
  counter,
  todos,
});

export default rootReducer;

 

 

๋ฆฌ๋“€์„œ๊ฐ€ 2๊ฐœ ์ด์ƒ์ผ ๊ฒฝ์šฐ์— combineReducer๋ผ๋Š” ์œ ํ‹ธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ rootReducer๋กœ ๋งŒ๋“ค์–ด ์ค€๋‹ค 

 

๋‚˜์ค‘์— ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ๋Š” 

 

 

import rootReducer from '/modules';

 

 

์ด๋Ÿฐ ์‹์œผ๋กœ importํ•˜์—ฌ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค 

 

 

์Šคํ† ์–ด ๋งŒ๋“ค๊ธฐ & Provider ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ๋•์Šค ์ ์šฉํ•˜๊ธฐ 

 

์šฐ์„  createStore๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ rootReducer๋ฅผ ๋ฆฌ๋“€์„œ๋กœ ์‚ฌ์šฉํ•จ์„ ์•Œ๋ ค์ฃผ๊ณ  ์Šคํ† ์–ด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค  

 

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import './index.css';
import App from './App';
import rootReducer from './modules';
import { Provider } from 'react-redux';

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>
  document.getElementById('root')
);

 

 

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์Šคํ† ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์ž‡๋„๋ก App ์ปดํฌ๋„ŒํŠธ๋ฅผ react-redux์—์„œ ์ œ๊ณตํ•˜๋Š” Provider ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ ์ค€๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” store๋ฅผ props๋กœ ์ „๋‹ฌํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค

 

 

 Redux DevTools์˜ ์„ค์น˜ ๋ฐ ์ ์šฉ

 

 

Redux DevTools๋Š” ๋ฆฌ๋•์Šค ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์ด๋ฉฐ, ํฌ๋กฌ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์„ค์น˜ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฆฌ๋•์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœํ•  ๋•Œ ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ๋”์šฑ ํŽธํ•˜๊ฒŒ ๋„์™€์ค€๋‹ค.

 

 

const store = createStore(
  rootReducer,
  window.devToolsExtension && window.devToolsExtension()
);

 

 

ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค์น˜ํ•˜๋ฉด ํŽธํ•˜์ง€๋งŒ ์–ด๋–ค ์˜ค๋ฅ˜์—์„œ์ธ์ง€ ์ž‘๋™์„ ํ•˜์ง€ ์•Š์•„ ์œ„์™€๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค..!

 

 

Connect ์‚ฌ์šฉํ•˜๊ธฐ 

 

CounterContainers ์ปดํฌ๋„ŒํŠธ

 

import React from 'react';
import Counter from '../components/Counter';


const CounterContainer = () => {
  return (
    <Counter />
  );
};

export default CounterContainer;

 

 

์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋•์Šค์™€ ์—ฐ๋™ํ•˜๊ธฐ์œ„ํ•ด react-redux์—์„œ ์ œ๊ณตํ•˜๋Š” connect ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค 

 

connect(mapStateToProps, mapDispatchToProps)(์—ฐ๋™ํ•  ์ปดํฌ๋„ŒํŠธ)

 

mapStateToProps๋Š” ๋ฆฌ๋•์Šค ์Šคํ† ์–ด ์•ˆ์˜ ์ƒํƒœ๋ฅผ ์ปดํฌ๋„ŒํŠธ์˜ props๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค

mapDispatchToProps๋Š” ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ์ปดํฌ๋„ŒํŠธ์˜ props๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค

 

 

const CounterContainer = ({number, increase, decrease}) => {
	return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
    );
};

const mapStateToProps = state => ({
  number: state.counter.number,
});

const mapDispatchToProps = dispatch => ({
  increase: () => {
    dispatch(increase());
  },
  decrease: () => {
    dispatch(dispatch());
  },
});
export default connect(
  mapStateToProps,
  mapDispatchToProps,(CounterContainer);
)

 

 

mapStateToProps๋Š” ์Šคํ† ์–ด์˜ ์ƒํƒœ๋ฅผ Props๋กœ ๋„˜๊ฒจ์ฃผ๊ณ  mapDispatchToProps๋Š” store์˜ ๋‚ด์žฅ ํ•จ์ˆ˜ dispatch๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ Props๋กœ ๋„˜๊ฒจ์ค€๋‹ค  

 

 

connect ํ•จ์ˆ˜๋ฅผ ์ต๋ช…ํ•จ์ˆ˜๋กœ ๊น”๋”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ 

 

connect ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์ต๋ช… ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•ด์„œ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋ณด์ž

 

 

const CounterContainer = ({number, increase, decrease}) => {
	return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
    );
};

const mapStateToProps = state => ({
  number: state.counter.number,
});

export default connect(
  state => ({
    number: state.counter.number,
  }),
  dispatch => ({
    increase: () => dispatch(increase()),
    decrease: () => dispatch(decrease()),
  }),
)(CounterContainer);

 

 

์ต๋ช… ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•ด์„œ ๋” ๊น”๋”ํ•ด์ง„ ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 

 

bindActionCreators๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ dispatch ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ 

 

 

์ปดํฌ๋„ŒํŠธ์—์„œ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋””์ŠคํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  dispatch๋กœ ๊ฐ์‹ธ๋Š” ์ž‘์—…์ด ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค ํŠนํžˆ ์•ก์…˜ ์ƒ์„ฌ ํ•จ์ˆ˜์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„ ์ง„๋‹ค๋ฉด ๋”๋”์šฑ ๋ฒˆ๊ฑฐ๋กœ์›Œ ์ง„๋‹ค ์ด๋ฅผ ๋” ํŽธํ•˜๊ฒŒ ํ•˜๊ธฐ์œ„ํ•˜์—ฌ 

๋ฆฌ๋•์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” bindActionCreators ์œ ํ‹ธ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด๋ณด์ž 

 

 

import React, { useCallback } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Counter from '../components/Counter';
import { increase, decrease } from '../modules/counter';


const CounterContainer = ({number, increase, decrease}) => {
	return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
    );
};

const mapStateToProps = state => ({
  number: state.counter.number,
});

export default connect(
  state => ({
    number: state.counter.number,
  }),
  dispatch => 
    bindActionCreators(
      {
        increase,
        decrease,
      },
      dispatch
    )
)(CounterContainer);

 

 

์œ„ ์ฒ˜๋Ÿผ ํ•˜๋ฉด bindActionCreators ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋” ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

 

mapDispatchToProps์— ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•จ์ˆ˜ ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋กœ ์ด๋ฃจ์–ด์ง„ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค .

์ด ๊ฒฝ์šฐ์—๋Š” bindActionCreators๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. 

 

 

 

import React, { useCallback } from 'react';
import { connect } from 'react-redux';
import Counter from '../components/Counter';
import { increase, decrease } from '../modules/counter';


const CounterContainer = ({number, increase, decrease}) => {
	return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
    );
};

const mapStateToProps = state => ({
  number: state.counter.number,
});

export default connect(
  state => ({
    number: state.counter.number,
  }),
  {
    increase,
    decrease,
  },
)(CounterContainer);

 

 

์œ„์™€ ๊ฐ™์ด ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋„ฃ์–ด์ฃผ๋ฉด connect ํ•จ์ˆ˜๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ bindActionCreators ์ž‘์—…์„ ๋Œ€์‹ ํ•œ๋‹ค

 

 

 

โœจ ๋ฆฌ๋•์Šค ๋” ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ 

 

 

 

redux-actions

 

redux-actions๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ๋”์šฑ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ๋•Œ switch๋ฌธ์ด ์•„๋‹Œ handleActions๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์•ก์…˜๋งˆ๋‹ค ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

$ yarn add redux-actions

 

 

CreateAction

 

 

counter.js

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

const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';

export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);

 

์œ„์™€ ๊ฐ™์ด createAction์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒˆ๊ฑฐ๋กญ๊ฒŒ ๋งค๋ฒˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ํ•„์š” ์—†์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

handleActions

 

๋ฆฌ๋“€์„œ ํ•จ์ˆ˜์˜ ๊ฐ€๋…์„ฑ์„ ๋†’๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด handleActions๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž

 

 

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

const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';

export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);

const initialState = {
  number: 0,
};

const counter = handleActions(
  {
    [INCREASE]: (state, action) => ({ number: state.number + 1 }),
    [DECREASE]: (state, action) => ({ number: state.number - 1 }),
  },
  initialState
);

export default counter;

 

 

handleActions ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ๊ฐ ์•ก์…˜์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๋„ฃ์–ด ์ค€๋‹ค 

 

 

 

์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒฝ์šฐ createAction ์‚ฌ์šฉํ•˜๊ธฐ 

 

createAction์œผ๋กœ ์•ก์…˜์„ ๋งŒ๋“ค๋ฉด ์•ก์…˜์— ํ•„์š”ํ•œ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋Š” payload๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค 

 

 

์˜ˆ ) 

const MY_ACTION = 'sample/MY_ACTION';
const myAction = createAction(MY_ACTION, text => `${text}`;
const actopn = myAction('hello world!');

/*
  ๊ฒฐ๊ณผ :
  { type: MY_ACTION, payload" 'hello world!' }
*/

 

 

์ด์ œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•„์š”๋กœํ•˜๋Š” ๊ฒฝ์šฐ์˜ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋ฅผ createAction ์œผ๋กœ ๋งŒ๋“ค์–ด ๋ณด์ž 

 

 

import { createAction } from 'redux-actions';

const CHANGE_INPUT = 'sample/CHANGE_INPUT'; // input์„ ๋ณ€๊ฒฝํ•˜๋Š” ์•ก์…˜
const INSERT = 'sample/INSERT' // ์ƒˆ๋กœ์šด todo๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์•ก์…˜

export const changeInput = createAction(CHANGE_INPUT, input => input);
export const insert = createAction(INSERT, text => ({
  id: id++,
  text,
  done: false,
}));

 

 

insert์˜ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์•ก์…˜ ๊ฐ์ฒด ์•ˆ์— ๋„ฃ์–ด ์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— text๋ฅผ ๋„ฃ์œผ๋ฉด 

text๋ฅผ ์ถ”๊ฐ€ํ•œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ค€๋‹ค

 

changeInput์˜ ๊ฒฝ์šฐ input => input ํ˜•ํƒœ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋„ฃ์—ˆ์ง€๋งŒ ์ด ์ž‘์—…์ด ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋‹ค. 

์ƒ๋žตํ•ด๋„ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•˜์ง€๋งŒ, ์ฝ”๋“œ๋ฅผ ๋ณด์•˜์„ ๋•Œ ์ด ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์–ด๋–ค ๊ฐ’์ด ํ•„์š”ํ•œ์ง€ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜์ž

 

 

handleActions๋กœ ๋ฆฌ๋“€์„œ๋ฅผ ์žฌ์ž‘์„ฑ ํ•ด๋ณด๊ธฐ

 

createAction์œผ๋กœ ๋งŒ๋“  ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ ๊ฐ’์„ ๊ฐ์ฒด์— ๋„ฃ์„ ๋•Œ ์ž„์˜์˜ ์ด๋ฆ„์œผ๋กœ ๋„ฃ๋Š” ๊ฒƒ์ด ์•„๋‹Œ,

action.payload๋ผ๋Š” ์ด๋ฆ„์„ ๊ณตํ†ต์ ์œผ๋กœ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค 

 

 

 

const todos = handleActions(
  {
    [CHANGE_INPUT]: (state, action) => ({ ...state, action.payload }),
    [INSERT]: (state, action) => ({
      ...state,
      todos: state.todos.concat(action.payload),
    }),
    [TOGGLE]: (state, action) => ({
      ...state,
      todos: state.todos.map((todo) =>
        todo.id === action.payload ? { ...todo, done: !todo.done } : todo
      ),
    }),
    [REMOVE]: (state, action) => ({
      ...state,
      todos: state.todos.filter((todo) => todo.id !== action.payload),
    }),
  },
  initialState
);

 

 

์•„๋ž˜์™€ ๊ฐ™์ด ๋น„๊ตฌ์กฐํ™” ํ• ๋‹น ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ Action ๊ฐ’์˜ payload ์ด๋ฆ„์„ ์ƒˆ๋กœ ์„ค์ •ํ•ด ์ฃผ๋ฉด payload๊ฐ€ ์–ด๋–ค ๊ฐ’์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์‰ฝ๊ฒŒ ํŒŒ์•…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

 

const todos = handleActions(
  {
    [CHANGE_INPUT]: (state, { payload: input }) => ({ ...state, input }),
    [INSERT]: (state, { payload: todo }) => ({
      ...state,
      todos: state.todos.concat(todo),
    }),
    [TOGGLE]: (state, { payload: id }) => ({
      ...state,
      todos: state.todos.map((todo) =>
        todo.id === id ? { ...todo, done: !todo.done } : todo
      ),
    }),
    [REMOVE]: (state, { payload: id }) => ({
      ...state,
      todos: state.todos.filter((todo) => todo.id !== id),
    }),
  },
  initialState
);

 

 

payload์˜ ๊ฐ’์ด ์–ด๋–ค ๊ฐ’์„ ๋œปํ•˜๋Š”์ง€ ํ•œ๋ˆˆ์— ์‰ฝ๊ฒŒ ํŒŒ์•…๋˜์–ด ๋ณด๊ธฐ ํŽธํ•ด์ง„๋‹ค !

 

 

 

Reference

(์ฑ…) ๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ  - ๊น€๋ฏผ์ค€ (VELOPERT)