Redux: API ํ˜ธ์ถœ์„ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2015๋…„ 07์›” 20์ผ  ยท  115์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: reduxjs/redux

๋กœ๊ทธ์ธ ์„ฑ๊ณต / ์˜ค๋ฅ˜ ํ๋ฆ„์„ ๋งŒ๋“ค๋ ค๊ณ ํ•˜์ง€๋งŒ ๋‚ด ์ฃผ์š” ๊ด€์‹ฌ์‚ฌ๋Š”์ด ๋…ผ๋ฆฌ๋ฅผ ๋„ฃ์„ ์ˆ˜์žˆ๋Š” ์œ„์น˜์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ €๋Š” actions -> reducer (switch case with action calling API) -> success/error on response triggering another action ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ์€ API ํ˜ธ์ถœ์—์„œ ์ž‘์—…์„ ํ˜ธ์ถœ ํ•  ๋•Œ ๊ฐ์†๊ธฐ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๊ฐ์†๊ธฐ

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
import Immutable from 'immutable';
import LoginApiCall from '../utils/login-request';

const initialState = new Immutable.Map({
  email: '',
  password: '',
}).asMutable();

export default function user(state = initialState, action) {
  switch (action.type) {
    case LOGIN_ATTEMPT:
      console.log(action.user);
      LoginApiCall.login(action.user);
      return state;
    case LOGGED_FAILED:
      console.log('failed from reducer');
      return state;
    case LOGGED_SUCCESSFULLY:
      console.log('success', action);
      console.log('success from reducer');
      break;
    default:
      return state;
  }
}

ํ–‰์œ„

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';

export function loginError(error) {
  return dispatch => {
    dispatch({ error, type: LOGGED_FAILED });
  };
}

/*
 * Should add the route like parameter in this method
*/
export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: LOGGED_SUCCESSFULLY });
    // router.transitionTo('/dashboard'); // will fire CHANGE_ROUTE in its change handler
  };
}

export function loginRequest(email, password) {
  const user = {email: email, password: password};
  return dispatch => {
    dispatch({ user, type: LOGIN_ATTEMPT });
  };
}

API ํ˜ธ์ถœ

 // Use there fetch polyfill
 // The main idea is create a helper in order to handle success/error status
import * as LoginActions from '../actions/LoginActions';

const LoginApiCall = {
  login(userData) {
    fetch('http://localhost/login', {
      method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: userData.email,
        password: userData.password,
      }),
    })
    .then(response => {
      if (response.status >= 200 && response.status < 300) {
        console.log(response);
        LoginActions.loginSuccess(response);
      } else {
        const error = new Error(response.statusText);
        error.response = response;
        LoginActions.loginError();
        throw error;
      }
    })
    .catch(error => { console.log('request failed', error); });
  },
};

export default LoginApiCall;
docs question

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋งˆ์ง€๋ง‰์œผ๋กœ ๋กœ๊ทธ์ธ API ํ˜ธ์ถœ์„ ์–ด๋””์— ๋„ฃ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์ด ๋ฐ”๋กœ dispatch => {} ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ์˜ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค. ๋ถ€์ž‘์šฉ!

๋˜ ๋‹ค๋ฅธ ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ ์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ž‘์—…๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';

export function loginError(error) {
  return { error, type: LOGGED_FAILED };
}

export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: LOGGED_SUCCESSFULLY });
    router.transitionTo('/dashboard');
  };
}

export function loginRequest(email, password) {
  const user = {email: email, password: password};
  return { user, type: LOGIN_ATTEMPT };
}

export function login(userData) {
  return dispatch =>
    fetch('http://localhost/login', {
      method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: userData.email,
        password: userData.password,
      }),
    })
    .then(response => {
      if (response.status >= 200 && response.status < 300) {
        console.log(response);
        dispatch(loginSuccess(response));
      } else {
        const error = new Error(response.statusText);
        error.response = response;
        dispatch(loginError(error));
        throw error;
      }
    })
    .catch(error => { console.log('request failed', error); });
}

๊ตฌ์„ฑ ์š”์†Œ์—์„œ

this.props.login(); // assuming it was bound with bindActionCreators before

// --or--

this.props.dispatch(login()); // assuming you only have dispatch from Connector

๋ชจ๋“  115 ๋Œ“๊ธ€

์ด๊ฒƒ์€ ๊ฑฐ์˜ ๋งž์ง€๋งŒ ๋ฌธ์ œ๋Š” _ ์ˆœ์ˆ˜ํ•œ ์•ก์…˜ ์ œ์ž‘์ž๋ฅผ ๋ถˆ๋Ÿฌ์„œ ์ผ์ด ์ผ์–ด๋‚  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•ก์…˜ ์ƒ์„ฑ์ž๋Š” _what_์ด ๋ฐœ์†ก๋˜์–ด์•ผ ํ•จ์„ ์ง€์ •ํ•˜๋Š” ํ•จ์ˆ˜์ผ๋ฟ์ž„์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

// CounterActions
export function increment() {
  return { type: INCREMENT }
}


// Some other file
import { increment } from './CounterActions';
store.dispatch(increment()); <--- This will work assuming you have a reference to the Store
increment(); <---- THIS DOESN'T DO ANYTHING! You're just calling your function and ignoring result.


// SomeComponent
import { increment } from './CounterActions';

@connect(state => state.counter) // will inject store's dispatch into props
class SomeComponent {
  render() {
    return <OtherComponent {...bindActionCreators(CounterActions, this.props.dispatch)} />
  }
}


// OtherComponent
class OtherComponent {
  handleClick() {
    // this is correct:
    this.props.increment(); // <---- it was bound to dispatch in SomeComponent

    // THIS DOESN'T DO ANYTHING:
    CounterActions.increment(); // <---- it's just your functions as is! it's not bound to the Store.
  }
}

์ด์ œ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋จผ์ € ๋ช…ํ™•ํžˆํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋น„๋™๊ธฐ์‹ dispatch => {} ์–‘์‹์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹จ ํ•˜๋‚˜์˜ ์ž‘์—…์„ ๋™ ๊ธฐ์ ์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ  ๋ถ€์ž‘์šฉ์ด์—†๋Š” ๊ฒฝ์šฐ ( loginError ๋ฐ loginRequest ๊ฒฝ์šฐ true)

์ด:

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';

export function loginError(error) {
  return dispatch => {
    dispatch({ error, type: LOGGED_FAILED });
  };
}

export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: LOGGED_SUCCESSFULLY });
    // router.transitionTo('/dashboard');
  };
}

export function loginRequest(email, password) {
  const user = {email: email, password: password};
  return dispatch => {
    dispatch({ user, type: LOGIN_ATTEMPT });
  };
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹จ์ˆœํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';

export function loginError(error) {
  return { error, type: LOGGED_FAILED };
}

// You'll have a side effect here so (dispatch) => {} form is a good idea
export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: LOGGED_SUCCESSFULLY });
    // router.transitionTo('/dashboard');
  };
}

export function loginRequest(email, password) {
  const user = {email: email, password: password};
  return { user, type: LOGIN_ATTEMPT };
}

๋‘˜์งธ, ๊ฐ์†๊ธฐ๋Š” _ ๋ถ€์ž‘์šฉ์ด์—†๋Š” ์ˆœ์ˆ˜ํ•œ ๊ธฐ๋Šฅ _์ด์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ์—์„œ API๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

์ด:

const initialState = new Immutable.Map({
  email: '',
  password: '',
  isLoggingIn: false,
  isLoggedIn: false,
  error: null
}).asMutable(); // <---------------------- why asMutable?

export default function user(state = initialState, action) {
  switch (action.type) {
    case LOGIN_ATTEMPT:
      console.log(action.user);
      LoginApiCall.login(action.user); // <------------------------ no side effects in reducers! :-(
      return state;
    case LOGGED_FAILED:
      console.log('failed from reducer');
      return state;
    case LOGGED_SUCCESSFULLY:
      console.log('success', action);
      console.log('success from reducer');
      break;
    default:
      return state;
  }

์•„๋งˆ๋„ ๋” ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค

const initialState = new Immutable.Map({
  email: '',
  password: '',
  isLoggingIn: false,
  isLoggedIn: false,
  error: null
});

export default function user(state = initialState, action) {
  switch (action.type) {
    case LOGIN_ATTEMPT:
      return state.merge({
        isLoggingIn: true,
        isLoggedIn: false,
        email: action.email,
        password: action.password // Note you shouldn't store user's password in real apps
      });
    case LOGGED_FAILED:
      return state.merge({
        error: action.error,
        isLoggingIn: false,
        isLoggedIn: false
      });
    case LOGGED_SUCCESSFULLY:
      return state.merge({
        error: null,
        isLoggingIn: false,
        isLoggedIn: true
      });
      break;
    default:
      return state;
  }

๋งˆ์ง€๋ง‰์œผ๋กœ ๋กœ๊ทธ์ธ API ํ˜ธ์ถœ์„ ์–ด๋””์— ๋„ฃ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์ด ๋ฐ”๋กœ dispatch => {} ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ์˜ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค. ๋ถ€์ž‘์šฉ!

๋˜ ๋‹ค๋ฅธ ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ ์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ž‘์—…๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';

export function loginError(error) {
  return { error, type: LOGGED_FAILED };
}

export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: LOGGED_SUCCESSFULLY });
    router.transitionTo('/dashboard');
  };
}

export function loginRequest(email, password) {
  const user = {email: email, password: password};
  return { user, type: LOGIN_ATTEMPT };
}

export function login(userData) {
  return dispatch =>
    fetch('http://localhost/login', {
      method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: userData.email,
        password: userData.password,
      }),
    })
    .then(response => {
      if (response.status >= 200 && response.status < 300) {
        console.log(response);
        dispatch(loginSuccess(response));
      } else {
        const error = new Error(response.statusText);
        error.response = response;
        dispatch(loginError(error));
        throw error;
      }
    })
    .catch(error => { console.log('request failed', error); });
}

๊ตฌ์„ฑ ์š”์†Œ์—์„œ

this.props.login(); // assuming it was bound with bindActionCreators before

// --or--

this.props.dispatch(login()); // assuming you only have dispatch from Connector

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด์™€ ๊ฐ™์€ ๋Œ€๊ทœ๋ชจ ์•ก์…˜ ์ƒ์„ฑ์ž๋ฅผ ์ž์ฃผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ, ๋น„๋™๊ธฐ์— ์‚ฌ์šฉํ•˜๋Š” ์•ฝ์†๊ณผ ํ˜ธํ™˜๋˜๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„์œ„ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฏธ๋“ค์›จ์–ด ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ธฐ์ˆ  ( dispatch => {} ์„œ๋ช…์ด์žˆ๋Š” ์•ก์…˜ ์ƒ์„ฑ์ž)์€ ํ˜„์žฌ Redux์— ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ 1.0์—์„œ๋Š” redux-thunk ๋ผ๋Š” ๋ณ„๋„์˜ ํŒจํ‚ค์ง€๋กœ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๊ทธ๊ฒƒ์—์žˆ๋Š” ๋™์•ˆ ๋‹น์‹ ์€ redux-promise-middleware ๋˜๋Š” redux-promise๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@gaearon : ๋ฐ•์ˆ˜ : ๋†€๋ผ์šด ์„ค๋ช…์ด์—ˆ์Šต๋‹ˆ๋‹ค! ;) ํ™•์‹คํžˆ ๋ฌธ์„œ๋กœ ๋งŒ๋“ค์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@gaearon ๊ต‰์žฅํ•œ ์„ค๋ช…! :ํŠธ๋กœํ”ผ:

@gaearon ์–ด๋–ค API ํ˜ธ์ถœ์„ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ํ•œ๊ณณ์— ์žˆ์–ด์•ผํ•˜๋Š” ๋„๋ฉ”์ธ ๋กœ์ง์ด ์•„๋‹Œ๊ฐ€? In Action ์ œ์ž‘์ž๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ์ง„์‹ค์˜ ๋‹จ์ผ ์†Œ์Šค๋ฅผ ๊นจ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€, ๋Œ€๋ถ€๋ถ„์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ์˜ ๊ฐ’์œผ๋กœ API ํ˜ธ์ถœ์„ ๋งค๊ฐœ ๋ณ€์ˆ˜ํ™”ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๋“  ๋…ผ๋ฆฌ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์„ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ๋ฆฌ๋“€์„œ (์›์ž ํ”Œ๋Ÿญ์Šค)์—์„œ API ํ˜ธ์ถœ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ ๋งค์šฐ ์œ ์šฉํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋“€์„œ (์›์ž ํ”Œ๋Ÿญ์Šค)์—์„œ API ํ˜ธ์ถœ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ ๋งค์šฐ ์œ ์šฉํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋กœ ์ธํ•ด ๊ธฐ๋ก / ์žฌ์ƒ์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ๋ถ€์ž‘์šฉ์ด์žˆ๋Š” ํ•จ์ˆ˜๋Š” ์ •์˜์ƒ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ณด๋‹ค ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. Redux๋ฅผ ์ด์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋””์ž์ธ์— ์™„์ „ํžˆ ๋ฐ˜๋Œ€๋ฉ๋‹ˆ๋‹ค. :-)

In Action ์ œ์ž‘์ž๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ์ง„์‹ค์˜ ๋‹จ์ผ ์†Œ์Šค๋ฅผ ๊นจ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค.

"๋‹จ์ผ ์ง„์‹ค ์†Œ์Šค"๋Š” ๋ฐ์ดํ„ฐ ๊ฐ€ ํ•œ ๊ณณ์— ์กด์žฌํ•˜๊ณ  ๋…๋ฆฝ์  ์ธ ์‚ฌ๋ณธ์ด ์—†์Œ์„ ์˜๋ฏธ

ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š” API ํ˜ธ์ถœ์„ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ๋…ผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ํ•œ๊ณณ์— ์žˆ์–ด์•ผํ•˜๋Š” ๋„๋ฉ”์ธ ๋กœ์ง์ด ์•„๋‹Œ๊ฐ€?

๋ฆฌ๋“€์„œ๋Š” ๋™์ž‘์— ์˜ํ•ด ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ์ด๋Ÿฌํ•œ ํ–‰๋™์ด ์–ด๋””์„œ ์‹œ์ž‘๋˜์—ˆ๋Š”์ง€์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ, ์•ก์…˜ ์ œ์ž‘์ž, ๊ธฐ๋ก ๋œ ์—ฐ์† ์„ธ์…˜ ๋“ฑ์—์„œ ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์•ก์…˜ ์‚ฌ์šฉ ๊ฐœ๋…์˜ ์•„๋ฆ„๋‹ค์›€์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  API ํ˜ธ์ถœ (๋˜๋Š” ํ˜ธ์ถœ๋˜๋Š” API๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋กœ์ง)์€ ๋ฆฌ๋“€์„œ๋ณด๋‹ค ๋จผ์ € ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด Redux๊ฐ€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ง€์›ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ Thunk ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์ƒํƒœ์—์„œ ์ฝ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

// Simple pure action creator
function loginFailure(error) {
  return { type: LOGIN_FAILURE, error };
}

// Another simple pure action creator
function loginSuccess(userId) {
  return { type: LOGIN_SUCCESS, userId };
}

// Another simple pure action creator
function logout() {
  return { type: LOGOUT };  
}


// Side effect: uses thunk middleware
function login() {
  return dispatch => {
    MyAwesomeAPI.performLogin().then(
      json => dispatch(loginSuccess(json.userId)),
      error => dispatch(loginFailure(error))
    )
  };
}


// Side effect *and* reads state
function toggleLoginState() {
  return (dispatch, getState) => {
    const { isLoggedIn } = getState().loginState;
    if (isLoggedIn) {
      dispatch(login());
    } else {
      dispatch(logout());
    }
  };
}

// Component
this.props.toggleLoginState(); // Doesn't care how it happens

์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ์™€ ๋ฏธ๋“ค์›จ์–ด๋Š” ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์„œ๋กœ๋ฅผ ๋ณด์™„ํ•˜๋„๋ก _ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค _.
๊ฐ์†๊ธฐ๋Š” ์ƒํƒœ ๋จธ์‹  ์ผ ๋ฟ์ด๋ฉฐ ๋น„๋™๊ธฐ์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋“€์„œ๋Š” ๋™์ž‘์— ์˜ํ•ด ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ฐธ์œผ๋กœ ์œ ํšจํ•œ ํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฒ„์ „์ด ๋ฌธ์„œ์— ํฌํ•จ๋  ๋•Œ๊นŒ์ง€ ํ›„์†์„ ์œ„ํ•ด ๋‹ค์‹œ ์—ด๊ฒ ์Šต๋‹ˆ๋‹ค.

: +1 :

๋ฆฌ๋“€์„œ๋Š” ์ƒํƒœ ๋จธ์‹ ์ด์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์•ก์…˜ ์ƒ์„ฑ์ž๋„ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค (ํ•˜์ง€๋งŒ ์•”์‹œ ์ ์œผ๋กœ).

์‚ฌ์šฉ์ž๊ฐ€ "์ œ์ถœ"๋ฒ„ํŠผ์„ ๋‘ ๋ฒˆ ํด๋ฆญํ–ˆ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” HTTP ์š”์ฒญ์„ ์„œ๋ฒ„ (์•ก์…˜ ์ƒ์„ฑ๊ธฐ)์— ๋ณด๋‚ด๊ณ  ์ƒํƒœ๋ฅผ "์ œ์ถœ ์ค‘"(๋ฆฌ๋“€์„œ์—์„œ)์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ๋กœ ๊ทธ๋ ‡๊ฒŒํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ชจ๋ธ์—์„œ ์•ก์…˜ ์ œ์ž‘์ž๋Š” ํ˜„์žฌ ์ƒํƒœ์— ๋”ฐ๋ผ ์ „๋‹ฌํ•  ์•ก์…˜์„ ์„ ํƒํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ "์ œ์ถœ"ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ-HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๊ฒฝ๊ณ ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ œ์–ด ํ๋ฆ„์€ ํšจ๊ณผ์ ์œผ๋กœ ๋‘ ๊ฐœ์˜ ์ƒํƒœ ๋จธ์‹ ์œผ๋กœ ๋ถ„ํ• ๋˜๊ณ  ๊ทธ์ค‘ ํ•˜๋‚˜๋Š” ์•”์‹œ ์ ์ด๋ฉฐ ๋ถ€์ž‘์šฉ์œผ๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด Flux ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์ธ ์›น ์•ฑ์˜ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋งค์šฐ ์ž˜ ์ฒ˜๋ฆฌํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณต์žกํ•œ ์ œ์–ด ๋กœ์ง์ด ์žˆ์œผ๋ฉด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ๋ชจ๋“  ์˜ˆ์ œ์—๋Š” ๋ณต์žกํ•œ ์ œ์–ด ๋กœ์ง์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—์ด ๋ฌธ์ œ๋Š” ๋‹ค์†Œ ์ˆจ๊ฒจ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/Day8/re-frame ์€ ์œ ์ผํ•œ FSM ์—ญํ• ์„ํ•˜๋Š” ๋‹จ์ผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€์žˆ๋Š” ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ์†๊ธฐ๋Š” ๋ถ€์ž‘์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ "์žฌ์ƒ"๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฅ๋ฏธ ๋กญ์Šต๋‹ˆ๋‹ค. https://github.com/Day8/re-frame/issues/86 ์—์„œ ์งˆ๋ฌธํ–ˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๊ฒƒ์ด ์ง„์งœ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉฐ ๊ณ„์†ํ•ด์„œ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์€ ๋†€๋ผ์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์–ด๋–ค ์†”๋ฃจ์…˜์ด ๋‚˜์˜ฌ์ง€ ๋ณด๋Š” ๊ฒƒ์€ ํฅ๋ฏธ ๋กญ์Šต๋‹ˆ๋‹ค.

ํ”„๋ ˆ์ž„ ๋ณ€๊ฒฝ ๋ฐ ๋ถ€์ž‘์šฉ์— ๋Œ€ํ•ด ๊ณ„์† ์•Œ๋ ค์ฃผ์„ธ์š”!

๋‚ด ์ฑ…์—๋Š” ๊ดœ์ฐฎ์€ Redux ์›น ์•ฑ์—๋Š” 3 ๊ฐ€์ง€ ์ƒํƒœ ์œ ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

1) ๊ตฌ์„ฑ ์š”์†Œ๋ณด๊ธฐ (React this.state). ์ด๊ฒƒ์€ ํ”ผํ•ด์•ผํ•˜์ง€๋งŒ ๋•Œ๋กœ๋Š” Redux์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜์žˆ๋Š” ์ผ๋ถ€ ๋™์ž‘์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

2) ์•ฑ ๊ณต์œ  ์ƒํƒœ, ์ฆ‰ Redux.state. ๋ณด๊ธฐ ๊ณ„์ธต์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ฑ์„ ์ œ๊ณตํ•˜๊ณ ๋ณด๊ธฐ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋กœ๊ฐ„์— "ํ†ต์‹ "ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ƒํƒœ๋Š” ๊ฒฐ์ •์ด์ด ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ActionCreators, Middleware, ๋ทฐ๊ฐ„์— "ํ†ต์‹ "ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ "๊ณต์œ "๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์™„์ „ํ•œ ์•ฑ ์ƒํƒœ ์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์ƒํƒœ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋น„์‹ค์šฉ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค (ํ–‰๋™ ์ธก๋ฉด์—์„œ).

3) ๋‹ค๋ฅธ ๋ถ€์ž‘์šฉ์„ ์ผ์œผํ‚ค๋Š” ๋ณต์žกํ•œ ๋ชจ๋“ˆ / libs / ์„œ๋น„์Šค๊ฐ€ ๋ณด์œ ํ•˜๋Š” ์ƒํƒœ. ๋ธ”๋ผ ๋‹ค๋ฅด๊ฐ€ ์„ค๋ช…ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ์ด๊ฒƒ์„ ์“ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ๋ฐ˜์‘ ๋ผ์šฐํ„ฐ๊ฐ€ ๋˜ ๋‹ค๋ฅธ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์ž์ฒด ์ƒํƒœ๊ฐ€์žˆ๋Š” ๋ธ”๋ž™ ๋ฐ•์Šค๋กœ ์ทจ๊ธ‰ํ•˜๊ฑฐ๋‚˜ react-router ์ƒํƒœ์˜ ์ผ๋ถ€๋ฅผ ์•ฑ ๊ณต์œ  ์ƒํƒœ (Redux.state)๋กœ ์ „ํ™˜ํ•˜๋„๋ก ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”์ฒญ๊ณผ ํƒ€์ด๋ฐ์„ ์˜๋ฆฌํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณต์žกํ•œ HTTP ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ Redux.state์˜ ์š”์ฒญ ํƒ€์ด๋ฐ ์„ธ๋ถ€ ์ •๋ณด์— ๊ด€์‹ฌ์ด ์—†์Šต๋‹ˆ๋‹ค. ActionCreators / Middlewares์˜์ด ๋ชจ๋“ˆ ๋งŒ Redux.state์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ Redux.state๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋‚ด ์š”์ฒญ์˜ ํƒ€์ด๋ฐ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ทฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด์ด ์ƒํƒœ๋ฅผ Redux.state๋กœ ๊ฐ€์ ธ์™€์•ผํ•ฉ๋‹ˆ๋‹ค.

@vladar AC / MW๊ฐ€ ์•”์‹œ ์  ์ƒํƒœ ๋จธ์‹ ์ด๋ผ๋Š” ์˜๋ฏธ์ž…๋‹ˆ๊นŒ? ์ž์ฒด์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์—ฌ์ „ํžˆ ๋‹ค๋ฅธ ๊ณณ์—์žˆ๋Š” ์ƒํƒœ์— ์˜์กดํ•˜๊ณ  ์žˆ์œผ๋ฉฐ์ด ์ƒํƒœ๊ฐ€ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ์ง„ํ™”ํ•˜๋Š”์ง€ ์ œ์–ด ๋…ผ๋ฆฌ๋ฅผ ์ •์˜ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๊นŒ? ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ํด๋กœ์ €๋กœ ๊ตฌํ˜„๋˜๊ณ  ์ž์ฒด ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์—ฌ ๋ช…์‹œ ์  ์ƒํƒœ ๋จธ์‹ ์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋˜๋Š” Redux.state๋ฅผ "๊ณต๊ฐœ ์ƒํƒœ"๋ผ๊ณ  ๋ถ€๋ฅด๊ณ  ๋‹ค๋ฅธ ์ƒํƒœ๋Š” ๋น„๊ณต๊ฐœ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์•ฑ์„ ๋””์ž์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์„ ๋น„๊ณต๊ฐœ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๊ณ  ๋ฌด์—‡์„ ๊ณต๊ฐœ ์ƒํƒœ๋กœ ์œ ์ง€ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ํ–‰์œ„์ž…๋‹ˆ๋‹ค. ์บก์Šํ™”์— ๋Œ€ํ•œ ์ข‹์€ ๊ธฐํšŒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฏ€๋กœ ์„œ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๋ฐฉ์‹์ด ์ง€์˜ฅ์ด๋˜์ง€ ์•Š๋Š” ํ•œ ์ƒํƒœ๋ฅผ ์—ฌ๋Ÿฌ ์žฅ์†Œ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ธ”๋ผ ๋‹ค๋ฅด

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ์†๊ธฐ๋Š” ๋ถ€์ž‘์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๋“ค์ด ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์— "์žฌ์ƒ"๊ธฐ๋Šฅ์„ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์ด ํฅ๋ฏธ ๋กญ์Šต๋‹ˆ๋‹ค

์‰ฝ๊ฒŒ ์žฌ์ƒํ•˜๋ ค๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ฒฐ์ •์ ์ด์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. Redux๊ฐ€ ์ˆœ์ˆ˜ํ•œ ๊ฐ์†๊ธฐ๋ฅผ ์š”๊ตฌํ•จ์œผ๋กœ์จ ๋‹ฌ์„ฑ ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ Redux.state๋Š” ์•ฑ์„ ๋น„ ๊ฒฐ์ •์  (๋น„๋™๊ธฐ) ๋ฐ ๊ฒฐ์ •์  ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค. ๋ณด๊ธฐ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋ฏธ์นœ ์ง“์„ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด Redux.state ์œ„์—์„œ bahavior๋ฅผ ์žฌ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ์ • ๋ก ์  ์ฝ”๋“œ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ์œ„ํ•œ ์ฒซ ๋ฒˆ์งธ ์ค‘์š”ํ•œ ๋ชฉํ‘œ๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋ฉ€๋ฆฌ ์ด๋™ํ•˜๊ณ  ์ž‘์—… ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ๋™๊ธฐ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Flux ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜์ ์œผ๋กœ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋‹ค๋ฅธ ๋ถ€์ž‘์šฉ ๋˜๋Š” ๋ณ€ํ˜• ์ฝ”๋“œ๋Š” ์—ฌ์ „ํžˆ ๊ฒฐ์ • ๋ก ์  ์ฒ˜๋ฆฌ๋ฅผ ์ค‘๋‹จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถ€์ž‘์šฉ ๋ฆฌ๋“€์„œ๋กœ ์žฌ์ƒ ๊ฐ€๋Šฅ์„ฑ์„ ๋‹ฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋น„ํ˜„์‹ค์ ์œผ๋กœ ์–ด๋ ต๊ฑฐ๋‚˜ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜ ์‹ค์ œ ํšจ๊ณผ๊ฐ€ ๊ฑฐ์˜์—†๋Š” ๋งŽ์€ ์ฝ”๋„ˆ ์ผ€์ด์Šค์—์„œ ๋ถ€๋ถ„์ ์œผ๋กœ ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‰ฌ์šด ์‹œ๊ฐ„ ์—ฌํ–‰์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Redux์—์„œ ์ˆ˜ํ–‰ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘์—… (ํ•ญ์ƒ ์–ด๋ ต์Šต๋‹ˆ๋‹ค)์„ ์žฌ์ƒํ•˜๋Š” ๋Œ€์‹  ์•ฑ ์ƒํƒœ์˜ ์Šค๋ƒ… ์ƒท์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

์‰ฌ์šด ์‹œ๊ฐ„ ์—ฌํ–‰์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Redux์—์„œ ์ˆ˜ํ–‰ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘์—… (ํ•ญ์ƒ ์–ด๋ ต์Šต๋‹ˆ๋‹ค)์„ ์žฌ์ƒํ•˜๋Š” ๋Œ€์‹  ์•ฑ ์ƒํƒœ์˜ ์Šค๋ƒ… ์ƒท์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

Redux DevTools ๋Š” ์Šค๋ƒ… ์ƒท๊ณผ ์ž‘์—…์„ ๋ชจ๋‘ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ž‘์—…์ด ์—†์œผ๋ฉด ๊ฐ์†๊ธฐ๋ฅผ ๋‹ค์‹œ๋กœ๋“œ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. DevTools๊ฐ€ ์ง€์›ํ•˜๋Š” ์›Œํฌ ํ”Œ๋กœ์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ์—ฌํ–‰์€ _ ํŒŒ๊ฒฌ ๋œ (์ตœ์ข…) ์›์‹œ ์ž‘์—… ์ˆ˜์ค€์—์„œ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ์ˆœํ•œ ์ž‘์—… ์ œ์ž‘์ž์—๊ฒŒ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค _. ์ด๋“ค์€ ์ผ๋ฐ˜ ๊ฐ์ฒด์ด๋ฏ€๋กœ ์™„์ „ํžˆ ๊ฒฐ์ •์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ, API ํ˜ธ์ถœ์„ "๋กค๋ฐฑ"ํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ๋ฌธ์ œ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ƒ์„ฑ ๋œ ์›์‹œ ์ž‘์—…์„ ๋กค๋ฐฑ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์ฒด์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์—ฌ์ „ํžˆ ๋‹ค๋ฅธ ๊ณณ์—์žˆ๋Š” ์ƒํƒœ์— ์˜์กดํ•˜๊ณ  ์žˆ์œผ๋ฉฐ์ด ์ƒํƒœ๊ฐ€ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ์ง„ํ™”ํ•˜๋Š”์ง€ ์ œ์–ด ๋…ผ๋ฆฌ๋ฅผ ์ •์˜ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๊นŒ?

๊ทธ๋ž˜, ๊ทธ๊ฒŒ ๋ฐ”๋กœ ๋‚ด๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๋ฐ”์•ผ. ๊ทธ๋Ÿฌ๋‚˜ ์ œ์–ด ๋กœ์ง์ด ์ค‘๋ณต ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ผ๋ถ€ ์ฝ”๋“œ (์œ„์˜ ์˜ˆ์ œ์—์„œ ๋‘ ๋ฒˆ ์ œ์ถœ ํด๋ฆญ).

function submit(data) {
  return (dispatch, getState) => {
    const { isSubmitting } = getState().isSubmitting;
    if (!isSubmitting) {
      dispatch(started(data));

      MyAPI.submit(data).then(
        json => dispatch(success(json)),
        error => dispatch(failure(error))
      )
    }
  }
}

function started(data) {
   return { type: SUBMIT_STARTED, data };
}

function success(result) {
  return { type: SUBMIT_SUCCESS, result };
}

function failure(error) {
  return { type: SUBMIT_FAILURE, error };
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ฐ์†๊ธฐ๊ฐ€ "isSubmitting"์ƒํƒœ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

const initialState = new Immutable.Map({
  isSubmitting: false,
  pendingData: null,
  error: null
});

export default function form(state = initialState, action) {
  switch (action.type) {
    case SUBMIT_STARTED:
      if (!state.isSubmitting) {
        return state.merge({
          isSubmitting: true,
          pendingData: action.data
        });
      } else {
        return state;
      }
  }
}

๋”ฐ๋ผ์„œ ๋‘ ๊ณณ์—์„œ ๋™์ผํ•œ ๋…ผ๋ฆฌ์  ๊ฒ€์‚ฌ๋ฅผ ๋ฐ›๊ฒŒ๋ฉ๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ์ด ์˜ˆ์ œ์—์„œ ์ค‘๋ณต์€ ์ตœ์†Œํ™”๋˜์ง€๋งŒ ๋” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์˜ˆ์˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ์˜ˆ์—์„œ ์ฒดํฌ๋Š” ๊ฐ์†๊ธฐ ์•ˆ์— ์žˆ์–ด์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋น ๋ฅด๊ฒŒ ๋ถˆ์ผ์น˜๋กœ ๋‚ด๋ ค๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(๊ทธ๊ฒŒ ๋‹น์‹ ์ด ๋งŒ๋“œ๋Š” ์š”์ ์ด๋ผ๋ฉด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ;-)

SUBMIT_STARTED ์•ก์…˜์ด ์ „๋‹ฌ๋˜์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค์—! isSubmitting์ด ์ด๋ฏธ ์ธ์ฝ”๋”ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— gaeron์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์•ก์…˜์ด ์–ด๋–ค ๋กœ์ง์˜ ๊ฒฐ๊ณผ ์ผ ๋•Œ ๊ทธ ๋กœ์ง์ด ๋ฆฌ๋“€์„œ์—์„œ ๋ณต์ œ๋˜์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๊ฐ์†๊ธฐ ์ฑ…์ž„์€ SUBMIT_STARTED๋ฅผ ์ˆ˜์‹  ํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด SUBMIT_STARTED๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์ฑ…์ž„์„ ์กŒ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  ์•ก์…˜ ํŽ˜์ด๋กœ๋“œ๋กœ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ ๊ฒฐ์ •์— ๋Œ€ํ•ด ์ฑ…์ž„์„์ง€๋Š” ๊ฒƒ์ด ํ•˜๋‚˜๋ผ๋Š” ๊ฒƒ์„ ํ•ญ์ƒ ๋ชฉํ‘œ๋กœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ๋Š” SUBMIT_STARTED ์‚ฌ์‹ค์„ ์ถ”๊ฐ€๋กœ ๋นŒ๋“œํ•˜๊ณ  ์ถ”๊ฐ€ ๋กœ์ง์œผ๋กœ ํ™•์žฅ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ์ด ๋กœ์ง์€ ๋‹ฌ๋ผ์•ผํ•ฉ๋‹ˆ๋‹ค. Fe :

case SUBMIT_STARTED:
  if (goodMood) loading...
  else nothing_happens

๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ์ฑ…์ž„ ์ ธ์•ผํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ๋•Œ๋•Œ๋กœ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ActionCreator, ๋ฏธ๋“ค์›จ์–ด, ๋…๋ฆฝํ˜• ๋ณตํ•ฉ ๋ชจ๋“ˆ, ๊ฐ์†๊ธฐ?

๊ฐ์†๊ธฐ์—์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๊ณ  ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ถ€์ž‘์šฉ / ๋น„ ๋™๊ธฐํ™”์— ๋Œ€ํ•œ ๊ฒฐ์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ AC / MW / somewhere_else๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ, ์ฆ‰ ๋ฆฌ๋“€์„œ ๋Œ€ ๋ฏธ๋“ค์›จ์–ด์™€ ๊ด€๋ จํ•˜์—ฌ ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ฐœ์ „ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

AC๋Š” state.isSubmitting์„ ์ง์ ‘ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋…ผ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ AC๋Š” state.isSubmitting์ด ๋…ผ๋ฆฌ์™€ ๋™๊ธฐํ™”๋˜๋„๋ก ๋ณด์žฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. AC ๋กœ์ง์ด ์ƒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ state.isSubmitted๋ฅผ true๋กœ ์„ค์ •ํ•˜๊ณ  ์ฝ๊ธฐ๊ฐ€ ๋Œ์•„์™”๋‹ค๋ฉด ๊ทธ ์ž์ฒด๋กœ ์„ค์ • ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ž ์žฌ์ ์œผ๋กœ์ด ์ „์ œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋‹ค๋ฅธ ๋…ผ๋ฆฌ๊ฐ€ ์žˆ์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ACTION์€ ๋™๊ธฐํ™” ๊ธฐ๋ณธ ์š”์†Œ ์ž์ฒด์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํ–‰๋™์€ ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•˜๊ณ  ํ”„๋กœํ† ์ฝœ์€ ๋ช…ํ™•ํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

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

๋ˆ„๊ตฐ๊ฐ€๋Š” ํ•ญ์ƒ ์˜ค๋ž˜๋œ ์ข…์† AC๋ฅผ ๋Š๋Š” ์ƒˆ๋กœ์šด ๊ฐ์†๊ธฐ๋ฅผ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AC๋ฅผ Redux ์ƒํƒœ์— ์ข…์†์‹œํ‚ค๊ธฐ ์ „์— ๋‘ ๋ฒˆ ์ƒ๊ฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

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

์–ด๋””๋กœ ๊ฐ€์•ผํ•˜๋‚˜์š”? ๊ฐœ๋…์ ์œผ๋กœ Redux ์ €์žฅ์†Œ์˜ ์ƒ์„ฑ์ž์— ๋ถˆ๋ณ€์˜ ์™ธ๋ถ€ ์ƒํƒœ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๊นŒ?

๋”ฐ๋ผ์„œ ๋งค์šฐ ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ AC์™€ ๊ฐ์†๊ธฐ ์‚ฌ์ด์˜ ๋…ผ๋ฆฌ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์‡ผ ์Šคํ† ํผ๋ผ๋Š” ๋ง์€ ์•„๋‹ˆ์ง€๋งŒ ์ผ๊ด€์„ฑ์ด ์—†์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ ๋จธ์‹ ์˜ ์š”์ ์€ ๋‚˜ํƒ€๋‚˜๋Š” ์ˆœ์„œ์— ๊ด€๊ณ„์—†์ด ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜๊ณ  ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

AC์—์„œ ์ด๋ฒคํŠธ์˜ ์ ์ ˆํ•œ ์ˆœ์„œ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ ์•”์‹œ ์ ์œผ๋กœ ์ƒํƒœ ์—”์ง„์˜ ์ผ๋ถ€๋ฅผ AC๋กœ ์ด๋™ํ•˜๊ณ  ๊ฐ์†๊ธฐ์™€ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ๊ทธ๊ฒƒ์€ ์„ ํ˜ธ์˜ ๋ฌธ์ œ ์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์Šคํ† ์–ด / ๋ฆฌ๋“€์„œ๊ฐ€ ํ•ญ์ƒ ์ผ๊ด€๋˜๊ฒŒ ์ž‘๋™ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์™ธ๋ถ€์— ์˜์กดํ•˜์ง€ ์•Š์„ ๋•Œ ํ›จ์”ฌ ๊ธฐ๋ถ„์ด ์ข‹์Šต๋‹ˆ๋‹ค.

AC๋ฅผ Redux ์ƒํƒœ์— ์ข…์†์‹œํ‚ค๊ธฐ ์ „์— ๋‘ ๋ฒˆ ์ƒ๊ฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋Š” ํ”ผํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค (๋ถ€์ž‘์šฉ์„ ๊ฐ์†๊ธฐ / ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋กœ ์˜ฎ๊ธฐ์ง€ ์•Š๊ณ ๋Š”).

"ํ•ซ ๋ฆฌ๋กœ๋”ฉ ๋˜๋Š” ๋ฆฌํ”Œ๋ ˆ์ด ๊ธฐ๋Šฅ ์‚ญ์ œ"์™€ "ํ•œ ๊ณณ์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ"๋ผ๋Š” ์ ˆ์ถฉ์•ˆ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์˜ ๊ฒฝ์šฐ re-frame ์ œ์•ˆ๊ณผ ๊ฐ™์€ ์‹ค์ œ FSM ๋˜๋Š” Statecharts๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ „์ž์˜ ๊ฒฝ์šฐ ํ˜„์žฌ Flux์—์„œ์™€ ๊ฐ™์ด ๋” ์ž„์‹œ์ ์ธ ์ œ์–ด ๋กœ์ง์ž…๋‹ˆ๋‹ค.

Re-frame์„ ํ†ตํ•ด (๋„ˆ๋ฌด ๋นจ๋ฆฌ) ์ฝ์—ˆ์œผ๋ฉฐ Redux์™€ ๊ฐ™์€ ์ข…๋ฅ˜์˜ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Re-frame view ์ปดํฌ๋„ŒํŠธ๋Š” Observable์„ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๊ณ , Events๋Š” Actions, Re-frame์€ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด (๋ทฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ตฌ์„ฑ๋จ)๋กœ ์ง์ ‘ ์ด๋ฒคํŠธ (์•ก์…˜)๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. Event Handler๋Š” ์ˆœ์ˆ˜ํ•˜๋ฉฐ Redux์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ.

๋ถ€์ž‘์šฉ ์ฒ˜๋ฆฌ๋Š” ๋งŽ์ด ๋…ผ์˜๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๊ทธ๊ฒƒ์„ ๋†“์ณค์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ œ๊ฐ€ ๊ฐ€์ •ํ•˜๊ณ ์žˆ๋Š” ๊ฒƒ์€ ๊ทธ๊ฒƒ๋“ค์ด ๋ฏธ๋“ค์›จ์–ด์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฃผ์š” ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๋ฆฌ๋“€์„œ)๋ฅผ ๊ฐ์‹ธ๊ณ  ์™ธ๋ถ€์—์„œ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ˜๋ฉด Redux ๋ฏธ๋“ค์›จ์–ด๋Š” ๋ฆฌ๋“€์„œ๋ฅผ ๊ฐ์‹ธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, Re-frame์€ ์ˆœ์ˆ˜ํ•œ ๊ฐ์†๊ธฐ์— ์ง์ ‘ ๋ถ€์ž‘์šฉ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ˜๋ฉด Redux๋Š” ๋ถ„๋ฆฌ ๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ Re-frame ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์‰ฝ๊ฒŒ ์žฌ์ƒํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๋Šฅํ•œ ๋ถˆ์ผ์น˜์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•  ๋•Œ ๊ณต์œ  ์ƒํƒœ๋ฅผ ๊ทผ๋ณธ ์›์ธ์œผ๋กœ ์ƒ๊ฐํ–ˆ๊ณ  Re-frame์ด ๋™์ผํ•œ ์œ„ํ—˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ฐจ์ด์ ์€ ๋ฏธ๋“ค์›จ์–ด์™€ ๊ฐ์†๊ธฐ๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ Re-frame์—์„œ ์™„๋ฃŒ๋˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๋ฆฌ๋“€์„œ)์— ์ง์ ‘ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.์ด ๊ฒฐ๊ณผ๋Š” ์ด๋ฒคํŠธ / ์•ก์…˜์œผ๋กœ ๊ธฐ๋ก๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์žฌ์ƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Redux๊ฐ€ ํ–‰๋™์˜ ํ˜•ํƒœ๋กœ ๊ทธ ์‚ฌ์ด์— ํ›„ํฌ๋ฅผ ๋„ฃ์„ ๋ฟ์ด๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋” ๋งŽ์€ ํƒ€์ดํ•‘ (์•ก์…˜ ์ƒ์„ฑ)์„ ํฌ์ƒํ•˜๋ฉด์„œ ๋” ๋งŽ์€ ์œ ์—ฐ์„ฑ๊ณผ ์•„๋งˆ๋„ ๊ทธ๊ฒƒ์„ ํ•  ์ˆ˜์žˆ๋Š” ๋” ๋งŽ์€ ๊ณต๊ฐ„์œผ๋กœ ๋ฆฌ ํ”„๋ ˆ์ž„์ดํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ๊ธฐ์ˆ ์ ์œผ๋กœ ๋‹ฌ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ.

๊ฒฐ๊ตญ Redux๊ฐ€ Re-frame๊ณผ ๋˜‘๊ฐ™์€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ๋ฅผ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ทธ ์•ˆ์— ์ผ๋ถ€ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ ๋‹ค์Œ ๊ฒฐ๊ณผ์™€ ํ•จ๊ป˜ ๊ฐ์†๊ธฐ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ณ  Reducer Middlewares ๋“ฑ์œผ๋กœ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DevTools๋ฅผ ์žƒ์–ด ๋ฒ„๋ฆฌ๊ณ  ๋” ๋งŽ์€ ์ปคํ”Œ ๋ง์„ํ•˜๋ฉด์„œ ์ข€ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ์ž…๋‹ˆ๋‹ค.

์ผ๋ถ€ ๋‹จ์ˆœํ™” (์•ก์…˜ ๊ฐ์†Œ)๋ณด๋‹ค Re-frame ์ ‘๊ทผ ๋ฐฉ์‹์— ์ƒ๋‹นํ•œ ์ด์ ์ด ์žˆ๋‹ค๋ฉด ๋” ๋งŽ์ด ์ƒ๊ฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋นจ๋ฆฌ ์ฝ์—ˆ๋‹ค ๊ณ  ๋งํ–ˆ๋“ฏ์ด ๋‚ด๊ฐ€ ํ‹€๋ ธ๋‹ค๋Š” ๊ฒƒ์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์—ด๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๋‚˜๋Š” ์•ฝ๊ฐ„ ํ‹€๋ ธ๋‹ค. ์ฐจ์ด์ ์€ Redux์™€ Re-frame ๊ตฌํ˜„์ด ์•„๋‹ˆ๋ผ ์‹ค์ œ๋กœ "๋ถ€์ž‘์šฉ์„ ๋„ฃ๋Š” ์œ„์น˜"์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๋ฆฌ๋“€์„œ)์—์„œ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์•ก์…˜ ์ƒ์„ฑ์ž๊ฐ€ ์ œ์–ด ํ๋ฆ„์— ์˜ํ–ฅ์„์ฃผ๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Redux์—์„œ๋„ fsm / statecharts๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ œ์–ด ํ๋ฆ„์„ ํ•œ๊ณณ์— ๋‘˜ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. @gaearon์€ ๊ทธ๊ฒƒ์„ ์•„์ฃผ ์ž˜ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค : Redux๋Š” ๋‹น์‹ ์˜ ๊ฐ์†๊ธฐ๊ฐ€ ์ˆœ์ˆ˜ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์žฌ์ƒ ๊ธฐ๋Šฅ์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Redux ๋””์ž์ธ์— ์œ„๋ฐฐ๋˜๋ฏ€๋กœ ๊ทธ๋ ‡๊ฒŒํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค (๊ฐ์†๊ธฐ์— ๋ถ€์ž‘์šฉ์„ ๋„ฃ๋Š” ๊ฒƒ).

Re-frame์€ ๋˜ํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ˆœ์ˆ˜ํ•˜๋‹ค๊ณ  ๋งํ•˜์ง€๋งŒ Readme์—์„œ๋„ HTTP ์š”์ฒญ์ด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์‹œ์ž‘๋œ๋‹ค๊ณ  ์–ธ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๊ฒƒ์€ ์ €์—๊ฒŒ ์•ฝ๊ฐ„ ๋ถˆ๋ถ„๋ช…ํ•˜์ง€๋งŒ ๊ทธ๋“ค์˜ ๊ธฐ๋Œ€๋Š” ๋‹ค๋ฅธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ์ž์—๊ฒŒ ๋ถ€์ž‘์šฉ์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ทธ๋“ค์ด ์žฌ์ƒ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฅ๋ฏธ ๋กญ์Šต๋‹ˆ๋‹ค (https://github.com/Day8/re-frame/issues/86์—์„œ ์š”์ฒญํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค).

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ถ€์ž‘์šฉ์„ ๊ฐ€์งˆ ์ˆ˜์žˆ์„ ๋•Œ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ @ tomkis1์ด ์–ธ๊ธ‰ ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ๋ฐ˜ํ™˜ ๋œ ์ƒํƒœ๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค (๋ชจ๋“  ์ด๋ฒคํŠธ์—์„œ ๊ฐ์†๊ธฐ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š์Œ).

ํ•ซ ๋ฆฌ๋กœ๋”ฉ์€ "๊ณผ๊ฑฐ"์ด๋ฒคํŠธ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์—ฌ์ „ํžˆ ์ž‘๋™ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์ผ๋ถ€ ์ƒˆ๋กœ์šด ์ƒํƒœ ๋ถ„๊ธฐ ๋งŒ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋””์ž์ธ์˜ ์ฐจ์ด๋Š” ๋ฏธ๋ฌ˜ํ•˜์ง€๋งŒ ์ €์—๊ฒŒ๋Š” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋“ค์ด ๋ถ€์ž‘์šฉ์„ ์ผ์œผํ‚ค๋Š” ๋ฏธ๋“ค์›จ์–ด๋กœ ์ˆœ์ˆ˜ํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ตฌ์„ฑํ•จ์œผ๋กœ์จ HTTP ์š”์ฒญ์„ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์„ฑ์€ ๋” ์ด์ƒ ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š์ง€๋งŒ ๋‚ด๋ถ€๋Š” ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€๋˜๋Š” ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด app-db (์ƒํƒœ) ๋Œ์—ฐ๋ณ€์ด์™€ ๋ถ€์ž‘์šฉ์„ ํ˜ผํ•ฉํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์„ ์ œ์•ˆํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ๋ณด๋‹ค ์‰ฝ๊ฒŒ โ€‹โ€‹ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๊ฒฝ์šฐ ํ•ซ ๋ฆฌ๋กœ๋“œ ๊ฐ€๋Šฅ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ฆ‰์‹œ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ•ด์•ผํ•˜๊ณ  ๊ทธ๊ฒƒ์€ Redux๊ฐ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค-์ด ๊ฒฐ๊ณผ๋ฅผ ์•ก์…˜์œผ๋กœ ๊ธฐ๋กํ•˜๊ณ  ๊ทธ๊ฒƒ์„ ๊ฐ์†๊ธฐ์— ์ „๋‹ฌํ•˜์‹ญ์‹œ์˜ค (๋“ฃ๊ธฐ).

Re-frame ๋ฏธ๋“ค์›จ์–ด๋Š” ๋Šฅ๋™์ ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Redux๋Š” ๋ฐ˜์‘์„ฑ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค (๋ชจ๋“  ์• ๋“œํ˜น ๊ฐ์†๊ธฐ๋Š” ๋ฏธ๋“ค์›จ์–ด / ac์˜ ๊ฒฐ๊ณผ๋ฅผ๋“ค์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ์ œ๊ฐ€ ๊นจ๋‹ซ๊ธฐ ์‹œ์ž‘ํ•œ ํ•œ ๊ฐ€์ง€๋Š” Flux์™€ ๋ฏธ๋“ค์›จ์–ด์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” AC๋Š” ์ปจํŠธ๋กค๋Ÿฌ์™€ ๋™์ผํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ดํ•ดํ–ˆ๋“ฏ์ด @ tomkis1 ์€ ๋ชจ๋“  ๋‹จ์ผ ๋Œ์—ฐ๋ณ€์ด์— ๋Œ€ํ•ด ์ˆ˜ํ–‰๋˜๋ฉด ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฏ€๋กœ ์ฃผ์–ด์ง„ ๊ฐ„๊ฒฉ์œผ๋กœ ์ €์žฅ ์ƒํƒœ๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ„

์ข‹์•„์š”, ๊ฐ์†๊ธฐ / ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์™„์ „ํ•œ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์œผ๋ฏ€๋กœ ๋™์ผํ•˜๊ฒŒ ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

@merk ์ฃผ๋ง์—๋Š” ์—ฌ๊ธฐ์— ์˜ค์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ๋„ ์›”์š”์ผ์— ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์ƒ๊ฐ์„ ์“ฐ๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Re-frame ๋ฌธ์„œ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์„œ๋ฒ„์™€ ๋Œ€ํ™” ํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค : https://github.com/Day8/re-frame#talking -to-a-server

๊ทธ๋ž˜์„œ ์ด๊ฒƒ์ด Redux์™€ ๋‹ค๋ฅธ ๊ณณ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ฐจ์ด๋Š” ์–ธ๋œป๋ณด๊ธฐ๋ณด๋‹ค ๋” ๊นŠ์Šต๋‹ˆ๋‹ค.

ํ , Redux์™€์˜ ์ฐจ์ด์ ์„ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ด๋Ÿฌํ•œ HTTP ์š”์ฒญ์— ๋Œ€ํ•œ on-success ๋˜๋Š” on-fail ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋‹จ์ˆœํžˆ ์ƒˆ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋„๋ก ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ ˆ๋Œ€๋กœ app-db๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ํ•ญ์ƒ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ๋ฅผ Action์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. Redux๋Š” ์ˆœ์ˆ˜ํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— ๋Œ€ํ•œ ํŠน๋ณ„ํ•œ ์ด๋ฆ„ ์ธ ๊ฐ์†๊ธฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์ฃผ๋ง์— ๋ญ”๊ฐ€ ๋น ์กŒ๊ฑฐ๋‚˜ ๋‡Œ๊ฐ€ ๋‹ค์šด ๋œ ๊ฒƒ ๊ฐ™์•„์š”.

์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋ฐฉ์‹ (๋Œ€๊ธฐ์—ด ๋ฐ ๋น„๋™๊ธฐ)์—์„œ ๋” ํฐ ์ฐจ์ด๋ฅผ ๋Š๋‚„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Redux๋Š” ์ƒํƒœ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์—…๋ณ„๋กœ ์ž‘์—… ๋™๊ธฐํ™” ๋ฐ ์ž ๊ธˆ ๋‹จ๊ณ„ ์ž‘์—…์„ ์‹คํ–‰ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ฐ˜๋ณตํ•ด์„œ ์žฌ์ƒํ•˜๋Š” ๊ฒƒ์ด ๋™์ผํ•œ ์ข…๋ฃŒ ์ƒํƒœ๊ฐ€ ๋ ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์ƒ์„ฑ์— ๋” ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ก์…˜์ด ํ•ญ์ƒ ์ˆœ์ˆ˜ํ•œ ์ฝ”๋“œ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” Redux์™€ ๋‹ฌ๋ฆฌ ์–ด๋–ค ์ด๋ฒคํŠธ๊ฐ€ ๋ถ€์ž‘์šฉ์„ ์œ ๋ฐœํ•˜๋Š”์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

@vladap ๋‚ด๊ฐ€ ๋ณธ ์ฐจ์ด์ ์„ ์š”์•ฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1.

  • Redux์—์„œ๋Š” ์ƒ์„ฑ์ž์—์„œ ์„œ๋ฒ„ ์š”์ฒญ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค (์ด ๋ฌธ์ œ์˜ ์›๋ž˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ @gaearon ์‘๋‹ต ์ฐธ์กฐ). ๊ฐ์†๊ธฐ๋Š” ์ˆœ์ˆ˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค
  • Re-frame์—์„œ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (reducer)์—์„œ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๊ฐ์†Œ ์ž)๋Š” ๋ถ€์ž‘์šฉ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2.

  • ์ฒซ ๋ฒˆ์งธ ๊ฒฝ์šฐ ์ œ์–ด ํ๋ฆ„์€ AC์™€ ๊ฐ์†๊ธฐ๋กœ ๋ถ„ํ• ๋ฉ๋‹ˆ๋‹ค.
  • ๋‘ ๋ฒˆ์งธ ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋“  ์ œ์–ด ํ๋ฆ„์ด ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ (๊ฐ์†Œ ๊ธฐ)์— ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ผ.

  • ์ œ์–ด ํ๋ฆ„์ด ๋ถ„ํ•  ๋œ ๊ฒฝ์šฐ-AC์™€ ๊ฐ์†๊ธฐ๊ฐ„์— ์กฐ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (์•”์‹œ ์  ์ผ์ง€๋ผ๋„) : AC๋Š” ๊ฐ์†๊ธฐ์— ์˜ํ•ด ์ƒ์„ฑ ๋œ ์ƒํƒœ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ๋Š” AC์—์„œ ์ด๋ฒคํŠธ์˜ ์ ์ ˆํ•œ ์ˆœ์„œ๋ฅผ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด AC์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ทธ ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋ฏ€๋กœ ๊ธฐ์ˆ ์ ์œผ๋กœ AC์™€ ๊ฐ์†๊ธฐ์˜ ์ปคํ”Œ ๋ง์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • ์ œ์–ด ํ๋ฆ„์ด ํ•œ๊ณณ์—์žˆ๋Š” ๊ฒฝ์šฐ-์ถ”๊ฐ€ ์กฐ์ •์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ / ๊ฐ์†Œ ๊ธฐ์—์„œ FSM ๋˜๋Š” ์ƒํƒœ ์ฐจํŠธ์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


    1. ์ˆœ์ˆ˜ํ•œ ๊ฐ์†๊ธฐ๋ฅผ ์ ์šฉํ•˜๊ณ  ๋ถ€์ž‘์šฉ์„ AC๋กœ ์ด๋™์‹œํ‚ค๋Š” Redux ๋ฐฉ์‹์œผ๋กœ ํ•ซ ๋ฆฌ๋กœ๋”ฉ ๋ฐ ๋ฆฌํ”Œ๋ ˆ์ด ๊ฐ€๋Šฅ

  • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๋ฆฌ๋“€์„œ)์—์„œ ๋ถ€์ž‘์šฉ์„ ๊ฐ–๋Š” ๋ฆฌ ํ”„๋ ˆ์ž„ ๋ฐฉ์‹์€ Redux์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ฆฌํ”Œ๋ ˆ์ด์˜ ๋ฌธ์„ ๋‹ซ์ง€ ๋งŒ (๋ฆฌ๋“€์„œ ์žฌํ‰๊ฐ€๋ฅผ ํ†ตํ•ด) ๋‹ค๋ฅธ (์•„๋งˆ๋„ ๋œ ๊ฐ•๋ ฅํ•œ) ์˜ต์…˜์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค- @ tomkis1์ด ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด

๊ฐœ๋ฐœ ๊ฒฝํ—˜์˜ ์ฐจ์ด์— ๊ด€ํ•ด์„œ๋Š” ๋น„๋™๊ธฐ ํ•ญ๋ชฉ (ํƒ€์ด๋จธ, ๋ณ‘๋ ฌ http ์š”์ฒญ, ์›น ์†Œ์ผ“ ๋“ฑ)์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋งŒ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋™๊ธฐํ™” ํ•ญ๋ชฉ์˜ ๊ฒฝ์šฐ ๋ชจ๋‘ ๋™์ผํ•ฉ๋‹ˆ๋‹ค (AC์—๋Š” ์ œ์–ด ํ๋ฆ„์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—).

๋‚ด ์š”์ ์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด ์ด๋Ÿฌํ•œ ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ์ค€๋น„ํ•ด์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋‹น์‹ ์„ ๋ฏธ์น˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์ธ ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฆฌ ํ”„๋ ˆ์ž„ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๊ณ  ์–ธ์  ๊ฐ€ Clojure๋ฅผ ๋ฐฐ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋‹น์‹ ์€ ๊ทธ๋žฌ์„ ๊ฒƒ์ด๋ฏ€๋กœ ๋” ๋งŽ์ด ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋…ธ๋ ฅํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

1.

Redux์—์„œ๋Š” ์ƒ์„ฑ์ž์—์„œ ์„œ๋ฒ„ ์š”์ฒญ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค (์ด ๋ฌธ์ œ์˜ ์›๋ž˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ @gaearon ์‘๋‹ต ์ฐธ์กฐ). ๊ฐ์†๊ธฐ๋Š” ์ˆœ์ˆ˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค
Re-frame์—์„œ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (reducer)์—์„œ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๊ฐ์†Œ ์ž)๋Š” ๋ถ€์ž‘์šฉ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ตต๊ฒŒ ๋งŒ๋“  ๋ฌธ์„œ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ webapi ํ˜ธ์ถœ์„ ์‹œ์ž‘ํ•œ ๋‹ค์Œ ์„ฑ๊ณต์‹œ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•ด์•ผํ•œ๋‹ค๊ณ  ๋ช…์‹œ ์ ์œผ๋กœ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ์ด ์ „๋‹ฌ ๋œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ด ์„ฑ๊ณต ์ด๋ฒคํŠธ๋Š” ๋ผ์šฐํ„ฐ (๋‚ด ์ƒ๊ฐ์— ๋””์ŠคํŒจ์ฒ˜์˜ ๋“ฑ์‹)๋กœ ์ „๋‹ฌ๋˜๋ฉฐ ์ฒ˜๋ฆฌ ํ•  ๋˜ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ˆœ์ˆ˜ํ•˜๊ณ  Redux ๊ฐ์†๊ธฐ์™€ ๋™์ผํ•˜๋ฉฐ ์ฒซ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ActionCreator์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์—๊ฒŒ ๊ทธ๊ฒƒ์€ ๋˜‘๊ฐ™๊ฑฐ๋‚˜ ์ค‘์š”ํ•œ ํ†ต์ฐฐ๋ ฅ์„ ๋ถ„๋ช…ํžˆ ๋†“์นœ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ ๊ฒฝํ—˜์˜ ์ฐจ์ด์— ๊ด€ํ•ด์„œ๋Š” ๋น„๋™๊ธฐ ํ•ญ๋ชฉ (ํƒ€์ด๋จธ, ๋ณ‘๋ ฌ http ์š”์ฒญ, ์›น ์†Œ์ผ“ ๋“ฑ)์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋งŒ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋™๊ธฐํ™” ํ•ญ๋ชฉ์˜ ๊ฒฝ์šฐ ๋ชจ๋‘ ๋™์ผํ•ฉ๋‹ˆ๋‹ค (AC์—๋Š” ์ œ์–ด ํ๋ฆ„์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—).

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ž‘์—…์€ ์‹ค์ œ๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ Redux์—์„œ ์žฌ์ƒํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์—์„œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์ˆœ์ˆ˜ ๊ฐ์†๊ธฐ๊ฐ€ ๋งŽ์„ ๋•Œ ์ฐจ์ด๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. Redux์—์„œ ์ƒํƒœ A, ์ผ๋ถ€ ์ž‘์—… ์‹œํ€€์Šค, ๋ฆฌ๋“€์„œ, ์žฌ์ƒ ๋ฐ ์ƒํƒœ B๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์„ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ๋ฆฌ๋“€์„œ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ํ•ซ ๋ฆฌ๋กœ๋“œํ•˜๊ณ  ์ƒํƒœ A์—์„œ ๋™์ผํ•œ ์ž‘์—… ์‹œํ€€์Šค๋ฅผ ์žฌ์ƒํ•˜๋ฉด ์ƒํƒœ C๋ฅผ ๊ฐ€์ ธ ์™€์„œ ์ฝ”๋“œ ๋ณ€๊ฒฝ์˜ ์˜ํ–ฅ์„ ์ฆ‰์‹œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. @ tomkis1 ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ๋Š” ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ ์œ„์— ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ตฌ์ถ• ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ , ์ž‘์—… ์‹œํ€€์Šค๋ฅผ ์ €์žฅํ•˜๊ณ , ์ž‘์—… ์‹œํ€€์Šค๋ฅผ ์ƒํƒœ A๋กœ ์ค„์ด๊ณ , ์ƒํƒœ B๋ฅผ ๊ฐ€์ ธ ์™€์„œ ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋™์ผํ•œ ์ƒํƒœ B๊ฐ€ ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์žฌ์ƒํ•˜์—ฌ ์ด๊ฒƒ์ด ์‚ฌ์‹ค์ด๋ฉฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์œผ๋กœ ์ธํ•ด ์•ฑ์ด ์ค‘๋‹จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์ตœ์„ ์˜ ํ…Œ์ŠคํŠธ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๊ณ  ๋งํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ Haskellers์ฒ˜๋Ÿผ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•˜๋“œ ์‹ค๋ฌด์ž๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š” Clojurists๊ฐ€ ๋ถ€์ž‘์šฉ์„ ์ตœ์†Œํ•œ ์–ด๋Š ์ •๋„์˜ ๊ตฌ์„ฑ ์—†์ด๋„ ์ˆœ์ˆ˜ ํ•  ์ˆ˜์žˆ๋Š” ์ฝ”๋“œ์™€ ํ˜ผํ•ฉํ•˜๋„๋ก ๊ถŒ์žฅํ•œ๋‹ค๋ฉด ์ƒ๋‹นํžˆ ๋†€๋ž„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ง€์—ฐ ํ‰๊ฐ€ / ๋ฐ˜์‘์„ฑ์€ ๋‹ค๋ฅธ ์ˆœ์ˆ˜ํ•œ ์ฝ”๋“œ์—์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ๋ถ€์ž‘์šฉ์ด์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ด๋™ํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ๊ฒŒ์œผ๋ฅธ ํ‰๊ฐ€๋Š” ํ•˜์Šค์ผˆ์ด ๋งˆ์นจ๋‚ด ์‹ค์šฉ์ ์ด์ง€ ์•Š์€ ๊ธฐ๋Šฅ์  ์ˆœ๋„ ๊ฐœ๋…์„ ์ ์šฉํ•˜์—ฌ ์‹ค์šฉ์ ์ธ ๊ฒƒ์„ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์–ป๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์™„์ „ํžˆ ์ˆœ์ˆ˜ํ•œ ํ”„๋กœ๊ทธ๋žจ์€ ๋งŽ์€ ๊ฒƒ์„ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ชจ๋‚˜ ๋”• ๊ตฌ์„ฑ ๋ฐ ๊ธฐํƒ€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ํ”„๋กœ๊ทธ๋žจ์ด ๋ฐ์ดํ„ฐ ํ๋ฆ„์œผ๋กœ ์ƒ์„ฑ๋˜๊ณ  ํŒŒ์ดํ”„ ๋ผ์ธ์˜ ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋ฅผ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์ฝ”๋“œ์—์„œ ์‹ค์ œ๋กœ ๋ถ€์ž‘์šฉ์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ํ”„๋กœ๊ทธ๋žจ์€ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ž‘์—…์— ๋Œ€ํ•œ ์„ค๋ช…์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋Š๋ฆฌ๊ฒŒ ์‹คํ–‰๋˜๋Š” ๋Ÿฐํƒ€์ž„์œผ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ๋ช…๋ นํ˜• ํ˜ธ์ถœ๋กœ ์‹คํ–‰์„ ํŠธ๋ฆฌ๊ฑฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ ์–ด๋„ ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ์กฐ๊ฐ๋„์—์„œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ดํ•ดํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ActionCreators ๋ฐ ๋ฐ˜์‘์„ฑ์œผ๋กœ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ทธ๋Ÿฐ ๋Ÿฐํƒ€์ž„์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ฉด์ฑ… ์กฐํ•ญ, ๊ทธ๊ฒƒ์„ ๋‹น์—ฐํ•˜๊ฒŒ ์—ฌ๊ธฐ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. FP์— ๋Œ€ํ•ด ๊ทธ๋ ‡๊ฒŒ ๋งŽ์ด ์ฝ์ง€ ์•Š์•„์„œ ์—ฌ๊ธฐ์—์„œ ์–ด๋–ค ์ข…๋ฅ˜์˜ ๊ถŒ์œ„๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋–จ์–ด์ ธ ์žˆ์„์ง€ ๋ชจ๋ฅด์ง€๋งŒ ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ๊ทธ ์š”์ ์„ ์ดํ•ดํ–ˆ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ์ด ์ „๋‹ฌ ๋œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. "๋ถ€์ž‘์šฉ"์ด๋ž€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ (๋ฆฌ๋“€์„œ)์—์„œ ์‹œ์ž‘๋œ HTTP ์š”์ฒญ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. IO๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ๋ฐ˜ํ™˜์— ์˜ํ–ฅ์„์ฃผ์ง€ ์•Š๋”๋ผ๋„ ๋ถ€์ž‘์šฉ์ž…๋‹ˆ๋‹ค. ์„ฑ๊ณต / ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ ์ƒํƒœ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ์ธก๋ฉด์—์„œ "๋ถ€์ž‘์šฉ"์„ ์˜๋ฏธํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๋‘ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ˆœ์ˆ˜ํ•˜๊ณ  Redux ๊ฐ์†๊ธฐ์™€ ๋™์ผํ•˜๋ฉฐ ์ฒซ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ActionCreator์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ๋Š” Action Creator์™€ ๋™๋“ฑํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์™œ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ๊ฐ์†๊ธฐ์—์„œ๋„ ๋˜‘๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด?

@ tomkis1 ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ๋Š” ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋™์˜ํ•˜๋‹ค. ์ด๊ฒƒ์ด ์ œ๊ฐ€ "๋‹ค๋ฅธ (์•„๋งˆ๋„ ๋œ ๊ฐ•๋ ฅํ•œ) ์˜ต์…˜"์„ ์ผ์„ ๋•Œ ์˜๋ฏธํ–ˆ๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ๋Š” Action Creator์™€ ๋™๋“ฑํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์™œ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ๊ฐ์†๊ธฐ์—์„œ๋„ ๋˜‘๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด?

ActionCreators๋Š” ์ˆœ์ˆ˜ ์•ฑ (๋‹ค์‹œ ์žฌ์ƒํ•  ์ˆ˜ ์žˆ์Œ)์—์„œ ๋ถ€์ž‘์šฉ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Redux๊ฐ€ ์„ค๊ณ„ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์†๊ธฐ์—์„œ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค (์•ˆ๋ฉ๋‹ˆ๋‹ค). ๋ถ€์ž‘์šฉ ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ ํ•  ์ˆ˜์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Redux์—์„œ ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ์€ AC ๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด์ž…๋‹ˆ๋‹ค. ๋ฆฌ ํ”„๋ ˆ์ž„์—์„œ ๋‚ด๊ฐ€ ๋ณผ ์ˆ˜์žˆ๋Š” ์œ ์ผํ•œ ์ฐจ์ด์ ์€ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ํ•˜๋Š” ์ผ๊ณผ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜๊ธฐ ์ „์— ์ด๋ฒคํŠธ (์•ก์…˜)๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

AC / ๋ฏธ๋“ค์›จ์–ด ๋Œ€์‹  ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ-util ๋ชจ๋“ˆ, ์„œ๋น„์Šค (์˜ˆ : Angular ์„œ๋น„์Šค), AC ๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋กœ ์ธํ„ฐํŽ˜์ด์Šคํ•˜๊ณ  API๋ฅผ ์ž‘์—…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ณ„๋„์˜ lib๋กœ ๋นŒ๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AC๋Š”์ด ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ํ•˜๊ธฐ์— ์ ํ•ฉํ•œ ์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. AC๋Š” ์ธ์ˆ˜์—์„œ ์•ก์…˜ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋‹จ์ˆœํ•œ ์ž‘์„ฑ์ž / ํŒฉํ† ๋ฆฌ ์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ˆœ์ˆ˜ ์ฃผ์˜์ž๊ฐ€๋˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ถ€์ž‘์šฉ ์ฝ”๋“œ๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ๋ฏธ๋“ค์›จ์–ด์— ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ์Šต๋‹ˆ๋‹ค. ActionCreator๋Š” ์ผ์ข…์˜ ์ปจํŠธ๋กค๋Ÿฌ ์ฑ…์ž„์— ๋Œ€ํ•œ ์ž˜๋ชป๋œ ์šฉ์–ด์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜์ด ์ฝ”๋“œ๊ฐ€ ํ•œ ์ค„์งœ๋ฆฌ webapi ํ˜ธ์ถœ์ด๋ฉด ๊ฐ„๋‹จํžˆ AC ๋‚ด๋ถ€์— ๋„ฃ๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์œผ๋ฉฐ ๊ฐ„๋‹จํ•œ ์•ฑ์˜ ๊ฒฝ์šฐ ๊ดœ์ฐฎ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

AC, ๋ฏธ๋“ค์›จ์–ด, ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ณ„์ธต์„ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด Facebook WebApiUtils๋Š” react-router๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋“ฃ๊ณ  Redux.state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ž‘์—…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์ด ๊ณ„์ธต์˜ ์ผ๋ถ€๊ฐ€๋ฉ๋‹ˆ๋‹ค. Relay๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์•ฑ /๋ณด๊ธฐ์— Redux๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ƒํƒœ). ๋Œ€๋ถ€๋ถ„์˜ ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ˜„์žฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์ƒ์ด ์ž˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ๋‚˜๋Š” โ€‹โ€‹๋ชจ๋“  ๊ฒƒ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์„œ๋น„์Šค, ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋“ฑ์ด ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์„ ํ™•์žฅํ•˜์—ฌ ์žฌ์ƒ ๊ฐ€๋Šฅํ•œ ์•ฑ์„ ๋นŒ๋“œ ํ•  ์ˆ˜์žˆ๋Š” ํ”Œ๋žซํผ์„ ํ•จ๊ป˜ ํ˜•์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ํ”Œ๋žซํผ์€ ๋ถ€์ž‘์šฉ์œผ๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ œ๊ฐ€ ์˜๋„์ ์œผ๋กœ ๋ถ€์ž‘์šฉ์„ ์˜ฎ๊ธฐ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์ด ํ”Œ๋žซํผ API๋ฅผ ์ž‘์—…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋‚ด ์•ฑ์€ ์ด๋Ÿฌํ•œ ์ž‘์—… ๊ฐœ์ฒด๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ์ด ํ”Œ๋žซํผ์— ๊ฐ„์ ‘์ ์œผ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค (์œ„์˜ ๊ฒŒ์‹œ๋ฌผ์—์„œ ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•œ Haskell ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋ ค๊ณ  ์‹œ๋„ ํ•จ). ์ด๊ฒƒ์€ ์ˆœ์ˆ˜์„ฑ์„ ๋‹ฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• (์•„๋งˆ๋„ ์ ˆ๋Œ€์ ์ธ ํ•™๋ฌธ์  ์˜๋ฏธ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ์Œ)์„ ๋‹ฌ์„ฑํ•˜์ง€๋งŒ ๋ถ€์ž‘์šฉ์„ ์œ ๋ฐœํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ผ์ข…์˜ ํ•ดํ‚น์ž…๋‹ˆ๋‹ค.

ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฒƒ์ด ์žˆ์ง€๋งŒ ์˜คํ•ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋…ผ๋ฆฌ์˜ ๊ฒฝ์šฐ ๋ชจ๋“  ๊ฒƒ์„ ํ•œ๊ณณ์— ๋‘๋Š” ๊ฒƒ์ด ์œ ์ตํ•˜๋‹ค๊ณ  ๋ง์”€ํ•˜์‹  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ƒ๋‹นํžˆ ๋ฐ˜๋Œ€๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด ์ „์ฒด ์•ก์…˜ ๋น„์ฆˆ๋‹ˆ์Šค๋Š” ๊ฐœ๋…์ ์œผ๋กœ DOM ์ด๋ฒคํŠธ์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ๋น„์ฆˆ๋‹ˆ์Šค ์ฝ”๋“œ๋ฅผ fe ๋ธŒ๋ผ์šฐ์ €๊ฐ€ mousemove ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ์ฝ”๋“œ์™€ ํ˜ผํ•ฉํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ๋‚˜๋Š” ์ด๋Ÿฌํ•œ ์ฑ…์ž„์ด ์ž˜ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— addListener ( 'mousemove', ...) ์œ„์—์„œ ์ž‘์—…ํ•˜๋Š” ๋ฐ ์ต์ˆ™ํ•ฉ๋‹ˆ๋‹ค. ์š”์ ์€ ๋‚ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋Œ€ํ•œ ์šฐ๋ ค๋ฅผ ์ž˜ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ActionCreators, ๋ฏธ๋“ค์›จ์–ด๋Š”์ด๋ฅผ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

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

๋”ฐ๋ผ์„œ ๋ชจ๋“  ๊ฒƒ์„ ํ•œ๊ณณ์— ๋ชจ์•„ ๋‘๋Š” ๊ฒƒ์€ ์‰ฌ์šด ์•ฑ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณต์žกํ•œ ์ผ๊ณผ๋Š” ์ •๋ฐ˜๋Œ€๋กœ ์ข‹์€ ๋ถ„๋ฆฌ๊ฐ€ ์œ ์ตํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์ด ์–ธ๊ธ‰ ํ•œ ๋‹น์‹ ์˜ ์š”์ ์ด๋‚˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ, ์•„๋งˆ๋„ ๋‚˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ˆœ์ˆ˜ํ•œ์ด ์ฝ”๋“œ์— ๋Œ€ํ•œ ์žฌ์ƒ ๋ฐ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ๋“€์„œ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์„ ํ‘œ์ค€ ํ˜•์‹์œผ๋กœ ์˜ฎ๊ธฐ๊ณ  ๊ฐ์†๊ธฐ ๊ตฌ์„ฑ์„ ๋Œ€์‹  ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋™์ผํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ์ด ์ „๋‹ฌ ๋œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

webapi ํ˜ธ์ถœ์„ ๊ฐ์†๊ธฐ ๋…ผ๋ฆฌ์™€ ํ˜ผํ•ฉํ•˜์—ฌ ํ•œ๊ณณ์—๋‘๊ธฐ๋ฅผ ์›ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๊ณต์‹œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์†กํ•  ๊ฒƒ์„ ์ œ์•ˆํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์‹œ ํ”„๋ ˆ์ž„์—์„œํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

webapi-> ๋งŽ์€ ๋…ผ๋ฆฌ-> webapi-> ๋งŽ์€ ๋…ผ๋ฆฌ-> ...-> ๊ฐ์†๊ธฐ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ, ํ•œ ๋ฒˆ์˜ ํด๋ฆญ์œผ๋กœ ์ „์ฒด ์ฒด์ธ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ์ƒํ™ฉ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ๋Œ€๋ถ€๋ถ„์˜ ๋…ผ๋ฆฌ๋Š” ์•„๋งˆ๋„ AC์—์žˆ์„ ๊ฒƒ์ด๋ฉฐ ๋ชจ๋“  ๋ถ€์ž‘์šฉ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋‚˜๋ˆ„์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‹น์‹ ์ด ๋งํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์„œ ํ•  ์ˆ˜์žˆ๋Š” ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์€ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ์„ ์œ„ํ•ด ๋…ผ๋ฆฌ๋ฅผ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ด์ง€๋งŒ AC ๋ฒ”์œ„์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๊ฐ„์ ‘์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ผ๋ จ์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋กœ ํ•  ์ˆ˜์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Promise ๋˜๋Š” Observable ์ฒด์ธ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฒฝํ—˜ ๋งŽ์€ Reduxers๋Š” ๊ทธ ์ƒ๊ฐ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ์˜๊ฒฌ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ( @gaearon , @johanneslumpe , @acdlite , @emmenko ...)

@vladap ๋‚˜๋Š”์ด ๋Œ€ํ™” ๊ฐ€์ด ๋ฌธ์ œ์˜ ์ฃผ์ œ์—์„œ ๋„ˆ๋ฌด ๋ฉ€๋ฆฌ ๋–จ์–ด์ง„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ์—ฌ๊ธฐ์—์„œ ๋‚ด ์˜๊ฒฌ์˜ ์š”์ ์„ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋งค์šฐ ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ AC์™€ ๊ฐ์†๊ธฐ ์‚ฌ์ด์˜ ๋…ผ๋ฆฌ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น ๋ฅธ ์˜ˆ :

์ƒํ™ฉ 1 : ํŽ˜์ด์ง€ ์–ด๋”˜๊ฐ€์— ์ƒ์œ„ 10 ๋ช…์˜ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ์ž ๋ชฉ๋ก์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ธ”๋กœ๊ทธ์—์„œ ๊ฒŒ์‹œ๋ฌผ ๋ฒ”์ฃผ๋ฅผ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค. ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œ๋˜๋ฉด ์„œ๋ฒ„์—์„œ์ด ์ž‘์„ฑ์ž ๋ชฉ๋ก์„ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์ตœ์‹  ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ƒํ™ฉ 2 : ๋‹น์‹ ์€ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์„ฑ์ž ๋ชฉ๋ก์€ ์—†์ง€๋งŒ ์ƒ์œ„ 10 ๊ฐœ ๋Œ“๊ธ€ ๋ชฉ๋ก์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์˜ ์ผ๋ถ€ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์‚ญ์ œํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œ๋˜๋ฉด ๋Œ“๊ธ€ ๋ชฉ๋ก์„ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ƒํƒœ ์—”์ง„ ์ˆ˜์ค€์—์„œ ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ์š”? (๋˜ํ•œ ๋„์›€์„ ๋ฐ›๊ธฐ ์œ„ํ•ด React ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ข‹์€ ์ƒํƒœ ์—”์ง„์€ ์ž์ฒด์ ์œผ๋กœ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค)

์˜ต์…˜ :
A)์ด ๋…ผ๋ฆฌ๋ฅผ AC์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ AC๋Š” CategoryApi (์‚ญ์ œ)๋ฅผ ํ„ฐ์น˜ํ•˜๊ณ  userList ์ฃผ ๋ฐ commentList ์ฃผ (ํ˜„์žฌ ์ฃผ์—์žˆ๋Š” ๋ชฉ๋ก ํ™•์ธ)๋ฅผ ์ฝ๊ณ  UserListApi ์™€ ๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค. CommentListApi (๋ชฉ๋ก ์ƒˆ๋กœ ๊ณ ์นจ) + TOP_AUTHORS_UPDATED ๋ฐ / ๋˜๋Š” TOP_COMMENTS_UPDATED ๋””์ŠคํŒจ์น˜. ๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ 3 ๊ฐœ์˜ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์„ ํ„ฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

B) ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ userList ๋ฐ commentList ๋„ฃ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ•ธ๋“ค๋Ÿฌ๋Š” ๋ชจ๋‘ DELETE_CATEGORY_SUCCESS ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹  ํ•œ ๋‹ค์Œ API ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  TOP_AUTHORS_UPDATED / TOP_COMMENTS_UPDATED ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ž์ฒด ๋„๋ฉ”์ธ์˜ ์„œ๋น„์Šค / ์ƒํƒœ ๋งŒ ํ„ฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ๋Š” ์•„๋งˆ๋„ ๋„ˆ๋ฌด ๋‹จ์ˆœ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ,์ด ์ˆ˜์ค€์—์„œ๋„ AC์—์„œ API ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒํ™ฉ์ด ๋œ ์˜ˆ๋ป์ง‘๋‹ˆ๋‹ค.

์ฐจ์ด์ ์€ ๋ฆฌ ํ”„๋ ˆ์ž„์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์™€ ๋‹ฌ๋ฆฌ ActionCreators๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‚ฌ์ „์— ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  DOM ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋‚˜์˜ AC ๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ตœ์ƒ์œ„ AC๋Š” ๋‹ค๋ฅธ AC๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. UserListApi ๋ฐ CommentListApi์— ๋Œ€ํ•ด ๋ณ„๋„์˜ AC๊ฐ€์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋„๋ฉ”์ธ์ด ๋” ์ž˜ ๋ถ„๋ฆฌ๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ•ญ์ƒ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” AC (์ปจํŠธ๋กค๋Ÿฌ์™€ ๊ฐ™์€)๊ฐ€ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ๊ฝค ๊ณ ์ „์ ์ธ ๋ช…๋ น ์ฝ”๋“œ์ด๋ฉฐ re-frame์€ ์™„์ „ํžˆ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜์ž…๋‹ˆ๋‹ค. ์•ฝ๊ฐ„์˜ ์ž‘์—…์„ ํ†ตํ•ด ์„ ํ˜ธํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹, ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜, ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ, cps ๋“ฑ์œผ๋กœ ๋Œ€์ฒด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@vladap ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ํฅ๋ฏธ๋กœ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฆฌ๋“€์„œ๊ฐ€ ๋ถ€์ž‘์šฉ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฆฌํ”Œ๋ ˆ์ด์—์„œ ๋ฌด์‹œ ๋  ์ˆ˜ ์žˆ๋„๋ก ๋ถ„๋ฆฌ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ ์„œ๋ช…์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. (state, action) => (state, sideEffects?) ์—ฌ๊ธฐ์„œ sideEffects๊ฐ€ ํด๋กœ์ €์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ปจํ…์ŠคํŠธ ํ”„๋ ˆ์ž„ ์›Œํฌ์— ๋”ฐ๋ผ ์ด๋Ÿฌํ•œ sideEffect๋ฅผ ํ‰๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์žฌ์ƒ์˜ ๊ฒฝ์šฐ).

๊ทธ๋Ÿฌ๋ฉด ์›๋ž˜ ๋ฌธ์ œ ์„ค๋ช…์˜ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export default function user(state = initialState, action) {
  switch (action.type) {
    case LOGIN_ATTEMPT:
      return [state, () => {LoginApiCall.login(action.user)}];
    case LOGGED_FAILED:
      // do something
      return state;
    case LOGGED_SUCCESSFULLY:
      // do something else
     return state;
    default:
      return state;
  }
}

(๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์€ ๊ฑฐ์˜ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค)

์ตœ์†Œํ•œ ์ œ์–ด ํ๋ฆ„์ด ํ•œ๊ณณ์— ์žˆ๊ณ  ๋ถ€์ž‘์šฉ์€ ํ•ญ์ƒ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค (๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ ๋‹ค๋ฅธ ์ž‘์—… / ์ด๋ฒคํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๋กœ์ง์ด ๊ฐ์†๊ธฐ์— ๋‚จ์•„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋งŽ์€ ์ฝ”๋“œ๊ฐ€ ์žฌ์ƒ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค).

์ผ๋ฐ˜ FSM ๋˜๋Š” Statechart์™€ ์œ ์‚ฌํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค (๊ฐ์†๊ธฐ / ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ ๊ตฌ์„ฑ ํฌํ•จ).

๋˜ํ•œ ์•ก์…˜ ์ƒ์„ฑ์ž์—์„œ ๋ฏธ๋ฆฌ ์ •์˜ ๋œ ์„œ๋ช…์œผ๋กœ ํด๋กœ์ €๋ฅผ ๋ฐ˜ํ™˜ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์ด ์ž ์žฌ์ ์œผ๋กœ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š”์ง€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ, ๋‚˜๋กœ์„œ๋Š” ๊ทธ๋Ÿด ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. (state, action) => (state, sideEffects?) ์—ฌ๊ธฐ์„œ sideEffects๋Š” ํด๋กœ์ €์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ปจํ…์ŠคํŠธ ํ”„๋ ˆ์ž„ ์›Œํฌ์— ๋”ฐ๋ผ ์ด๋Ÿฌํ•œ sideEffect๋ฅผ ํ‰๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์žฌ์ƒ์˜ ๊ฒฝ์šฐ).

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ Elm์ด (State, Action) => (State, Request?) ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์•„์ง ์–ด๋–ค ์˜ˆ๋„ ๋ณด์ง€ ๋ชปํ–ˆ์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€ ์ด๊ฒƒ์„ ํƒ๊ตฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ž์œ ๋กญ๊ฒŒ ๋Š๋ผ์‹ญ์‹œ์˜ค.

์˜๊ฐ์„ ์–ป์„ ์ˆ˜์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์ ‘๊ทผ๋ฒ•์€ Actor ๋ชจ๋ธ ( Akka Persistance , PersistentFSM) ์œ„์— ์ด๋ฒคํŠธ ์†Œ์‹ฑ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ๋งํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ๋‹ค๋ฅธ ์‹œ๋„๋ฅผ ์•„๋Š” ๊ฒƒ์ด ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์•กํ„ฐ๋Š” ๋ถ€์ž‘์šฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ธฐ์–ตํ•˜๋Š” ๊ฒฝ์šฐ ์žฌ์ƒ ๋ฐฉ๋ฒ•์„ ๋ช…์‹œ์ ์ธ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์žฌ์ƒ ๊ธฐ๋Šฅ์„ ์ œ์ณ๋‘๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚˜๋Š” ๋‚ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์•ก์…˜ ๋กœ๊ทธ ์•ž์—๋‘๊ณ  ํ•œ๊ณณ์— ๋‘๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœํ•ฉ๋‹ˆ๋‹ค. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ƒํƒœ ๋จธ์‹  ๋˜๋Š” ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์€ ๋ณต์žกํ•œ ๊ฒฐ์ •์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ด๋ฏธ ํ•ด๊ฒฐ ๋œ FACTS (์•ก์…˜) ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. Reducer๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ„๋‹จํ•œ ์—…๋ฐ์ดํŠธ ํ”„๋กœ๊ทธ๋žจ์ด๋ฉฐ ์ฃผ์š” ์ฑ…์ž„์€ Redux.state์— ์ž‘์—… ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๋ช‡ ๊ฐ€์ง€ ๋…ผ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์‚ฌ์‹ค์„ ๋‹ค๋ฅด๊ฒŒ ํ•ด์„ํ•˜์—ฌ ์‚ฌ์‹ค (์•ก์…˜) ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ๊ด€์ ์„ ์–ป์–ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฑ…์ž„์„ ๋ถ„๋‹ดํ•˜๊ธฐ ์œ„ํ•ด ์ €๋„ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ƒ๊ฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์—์„œ ์žฌ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ž ์žฌ์ ์œผ๋กœ ์–ด๋–ค ์ฝ”๋“œ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? Fe๋Š” ๊ณ„์‚ฐ ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ, ๋ณด์•ˆ์ƒ์˜ ์ด์œ , ์ธํ…”๋ฆฌ์ „์Šค ์†์„ฑ์„ ์ˆจ๊ธฐ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋Š๋ฆฐ ์žฅ์น˜๋ฅผ ๋” ์ž˜ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋ทฐ ๋ ˆ์ด์–ด์— ๋ฐ”์ธ๋”ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ๋“€์„œ์—์„œ ์„œ๋ฒ„๋กœ ๋กœ์ง์„ ์‰ฝ๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ž‘์—… ๋กœ๊ทธ ์•ž์— ์ž‘์„ฑ๋˜๋ฉด ๋™์ผํ•œ ์ž‘์—… ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜๋˜๋Š” REST ํ˜ธ์ถœ๋กœ ๋Œ€์ฒด ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‚ด ๋ทฐ ๋ ˆ์ด์–ด๊ฐ€ ์ž‘๋™ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค (์•„๋งˆ๋„).

๋‹จ์ ์€ Akka Persistance์™€ ๋‹ฌ๋ฆฌ์ด ์ฝ”๋“œ๋ฅผ ์žฌ์ƒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ธ์  ๊ฐ€๋Š” Elm์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ณ  ๊ท€ํ•˜์˜ ์ œ์•ˆ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@gaearon Elm์„ //gist.github.com/evancz/44c90ac34f46c63a27ae- ๋น„์Šทํ•œ ์•„์ด๋””์–ด (ํ•˜์ง€๋งŒ ํ›จ์”ฌ ๋” ๊ณ ๊ธ‰).

์ž‘์—… (http, db ๋“ฑ) ๋ฐ ํšจ๊ณผ (์ž‘์—… ๋Œ€๊ธฐ์—ด)์˜ ๊ฐœ๋…์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ "๋ฆฌ๋“€์„œ"๋Š” ์‹ค์ œ๋กœ ์ƒˆ๋กœ์šด ์ƒํƒœ์™€ ํšจ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•œ ๋ฉ‹์ง„ ์ ์€ (๊ทธ๋ฆฌ๊ณ  ์ €๋Š” ์ด๋Ÿฐ ์‹์œผ๋กœ ์ƒ๊ฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค)-๊ฐ์†๊ธฐ๋ฅผ ์—ฐ๊ฒฐํ•˜๋ฉด์„œ ์ž‘์—…์„ ์ˆ˜์ง‘ ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด-๋‚˜์ค‘์—์ด ๋ชฉ๋ก์— ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์ ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. http ์š”์ฒญ์„ ์ผ๊ด„ ์ฒ˜๋ฆฌํ•˜๊ณ  DB ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ž˜ํ•‘ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋˜๋Š” ํšจ๊ณผ์— ๋Œ€ํ•œ ๋ฉ์ฒญ์ด ์ธ "์žฌ์ƒ ๊ด€๋ฆฌ์ž"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@merk ๋‚˜๋Š” ๋Œ€๋ถ€๋ถ„์ด ์ด๋ฏธ ์ž‘์„ฑ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ž์œจ์  ์ธ ๋ถ€์ž‘์šฉ ์ฝ”๋“œ๊ฐ€ ์•„๋งˆ๋„ ๊ฐ€์žฅ ๊นŒ๋‹ค๋กœ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„ ์—ฌํ–‰์ด ๋™์ผํ•œ ์ฝ”๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ  ๊ฐ„๊ฒฉ์ด ์žฌ์ƒ ๋ชจ๋“œ์—์„œ๋„ ์‹œ์ž‘๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ๊ฐ„๊ฒฉ์ด ์‹œ๊ฐ„ ์—ฌํ–‰๊ณผ ๋™๊ธฐํ™”๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์ƒ์‹œ ํ˜ผ๋ž€์„ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต๋˜๋Š” ํ† ํฐ ๋ฐ ๋งŒ๋ฃŒ ์นด์šดํŠธ ๋‹ค์šด์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ธฐ์ˆ ์ ์œผ๋กœ Redux.state์—์žˆ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž ์•ฑ์— ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ž์‹ ์—๊ฒŒ ๋งž๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์˜ต์…˜์€ ๋กœ๊ทธ์ธ AC์—์„œ ๋งŒ๋ฃŒ ์นด์šดํŠธ ๋‹ค์šด์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ ๋์—†์ด ์‹คํ–‰๋˜๊ณ  ์•ฑ๊ณผ ํ•จ๊ป˜ ์ฃฝ๊ฑฐ๋‚˜ ๋กœ๊ทธ ์˜คํ”„๊ฐ€์ด๋ฅผ ์ •๋ฆฌํ•ด์•ผํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๊ฒฉ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋ฉด ํ† ํฐ์„ ํ™•์ธํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋งŒ๋ฃŒ๋˜๋ฉด LOGIN_EXPIRED ์ž‘์—…์„ ์ „๋‹ฌํ•˜๊ณ  ์ˆ˜์‹  ๊ฐ์†๊ธฐ๊ฐ€ ์‚ฌ์šฉ์ž ์„ธ์…˜์„ ์ง€์šฐ๊ณ  ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ผ์šฐํ„ฐ ์ „ํ™˜์„ / login์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ํƒ€์‚ฌ lib๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ์šฐ๋ ค๋ฅผ ์œ„์ž„ํ•˜๊ณ  ํ•ด๋‹น API๋ฅผ LOGIN_EXPIRED ์ž‘์—…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ๋ทฐ ๋ ˆ์ด์–ด์—์„œ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ณ  ์—ฌ๊ธฐ์— ํ† ํฐ ๋ฐ ์นด์šดํŠธ ๋‹ค์šด ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

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

์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋”ฐ๋ผ์ด ์ƒํƒœ๋Š” ๋กœ๊ทธ์ธ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณดํ˜ธํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์  ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งค์šฐ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ด๋ฉฐ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ƒํƒœ๊ฐ€ ๋ทฐ ๋ ˆ์ด์–ด์— ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฐ˜์‘ ๋ผ์šฐํ„ฐ ์œ„์น˜ ์ƒํƒœ๊ฐ€ ์ฃผ๋ณ€์˜ ์ผ๋ถ€ ์˜ˆ์—์„œ Redux.state์— ๋ณต์ œ๋˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ Redux.state์— ๋ณต์ œํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ์ฃผ์™€ ํŒ€์ด ์ž‘๊ณ  ์ž˜ ํ–‰๋™ํ•œ๋‹ค๋ฉด ํ•œ๊ณณ์— ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

ํŠธ์œ— ๋‹ด์•„ ๊ฐ€๊ธฐ

์™€, ๊ทธ ๋Š๋ฆ… ๋‚˜๋ฌด ์š”์ ์€ ์ •๋ง ๋ฉ‹์ ธ์š”! ๋˜ํ•œ Cycle.js "๋“œ๋ผ์ด๋ฒ„"์•„ํ‚คํ…์ฒ˜๋ฅผ ์ƒ๊ฐ ๋‚˜๊ฒŒํ•ฉ๋‹ˆ๋‹ค.

@merk ์‚ฌ์‹ค, ์ž์œจ LOGIN_EXPIRED๋Š” ๋ฆฌํ”Œ๋ ˆ์ด์— ํฐ ์˜ํ–ฅ์„์ฃผ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ์•ก์…˜ ๋กœ๊ทธ์˜ ๋์— ๋“ค์–ด๊ฐ€์„œ ๋ฆฌํ”Œ๋ ˆ์ด์— ์˜ํ•ด ์ฆ‰์‹œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๊ณ  ์•„๋งˆ๋„ ์•ก์…˜ ๋กœ๊ทธ์— ์ „ํ˜€ ๋„์ฐฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.-๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์žฌ์ƒ์ด ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๋Š”์ง€.

@gaeron ์ƒ์œ„ ์ˆ˜์ค€์—์„œ Elm๊ณผ Cycle์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜๋ฉด ์„ค๋ช…ํ•˜๋ ค๋Š” ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํ”Œ๋žซํผ์„ ์ œ๊ณตํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.์ด ํ”Œ๋žซํผ์„ ์„œ๋น„์Šค ๊ณ„์ธต (http, db ...)์œผ๋กœ ํ™•์žฅํ•˜์—ฌ ์•ฑ์šฉ ํ”Œ๋žซํผ์„ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์„œ๋น„์Šค ๊ณ„์ธต๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ณ  ์ˆœ์ˆ˜ํ•œ ์•ฑ์ด ๊ฐ„์ ‘์ ์œผ๋กœ ํ†ต์‹  ํ•  ์ˆ˜ ์žˆ๋„๋กํ•˜๋Š” ์ผ์ข…์˜ ์ ‘์ฐฉ์ œ๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ๋‚ด ์•ฑ์ด ์›ํ•˜๋Š” ์ž‘์—…์„ ์„ค๋ช… ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ ์‹คํ–‰ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค (Cycle ๋“œ๋ผ์ด๋ฒ„๋กœ ์ „์†ก ๋œ ๋ฉ”์‹œ์ง€, Elm Effects ์ž‘์—… ๋ชฉ๋ก ํฌํ•จ). ๋‚ด ์•ฑ์ด ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ "ํ”„๋กœ๊ทธ๋žจ"์„ ๋นŒ๋“œํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (๋ฐ์ดํ„ฐ ๋งŒํŠธ๋ผ๋กœ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ƒ๊ธฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค). ๊ทธ๋Ÿฐ ๋‹ค์Œ ์‹คํ–‰์„ ์œ„ํ•ด ์„œ๋น„์Šค ๊ณ„์ธต์œผ๋กœ ์ „๋‹ฌ๋˜๊ณ  ๋‚ด ์•ฑ์€์ด "ํ”„๋กœ๊ทธ๋žจ"์˜ ๊ฒฐ๊ณผ์—๋งŒ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ƒํƒœ๋กœ.

@merk : ๋”. ํ† ํฐ ๋ฐ ๋งŒ๋ฃŒ๊ฐ€ Redux.state / ๋˜๋Š” ๋‹ค๋ฅธ js ์„œ๋น„์Šค์˜ ์–ด๋Š ๊ณณ์— ๋‚˜ ๋ฐฐ์น˜๋˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ ํƒญ์—์„œ ์•ฑ์„ ์—ด ๋•Œ ์ „์†ก๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š”์ด ์ƒํƒœ๊ฐ€ ์‹ค์ œ๋กœ SessionStore์— ์žˆ์–ด์•ผํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ ์—†์ด๋„ ํ† ํฐ ๋งŒ๋ฃŒ๊ฐ€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ฆ‰์‹œ ์ •๋ฆฌํ•˜๊ณ  / login์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€ ์•Š์„ ๋•Œ ์ƒํƒœ๊ฐ€ ๋ถ„๋ฆฌ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ†ตํ•ด ์„œ๋ฒ„๋ฅผ ๋งŒ์ง€์ง€ ์•Š์„ ๋•Œ๊นŒ์ง€ (์บ์‹œ ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถฉ๋ถ„ ํ•จ) ๊ณ„์† ์ž‘์—… ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ LOGIN_EXPIRED ์ž‘์—…์€ ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ•œ ํ›„์— ๋งŒ โ€‹โ€‹ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. Redux.state๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋Š” isLogged ์ƒํƒœ๋Š” ์œ ํšจํ•œ ํ† ํฐ์ด ์กด์žฌ ํ•จ์„ ์˜๋ฏธ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Redux.state์˜ isLogged ์ƒํƒœ๋Š” ๋ Œ๋”๋ง ํ•  ํ•ญ๋ชฉ์„ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ† ํฐ ์ฃผ๋ณ€์˜ ์ƒํƒœ๋Š” ๋ทฐ ๋ ˆ์ด์–ด์— ์ˆจ๊ฒจ ์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ทฐ ๋ ˆ์ด์–ด์— ์˜ํ–ฅ์„์ฃผ๋Š” ๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ  ์•ก์…˜๊ณผ ๋ฆฌ๋“€์„œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์•ก์…˜ ์ƒ์„ฑ์ž ์ˆ˜์ค€์—์„œ๋งŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

@vladar ๋‚˜๋Š” ๋‹น์‹ ์˜ ์ผ๋ฐ˜์ ์ธ ์š”์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ „์— ๊นจ๋‹ซ์ง€ ๋ชปํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ์—์„œ ์ž‘์—… ์ƒ์„ฑ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ผ๋ถ€ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ’์€ ๋ Œ๋”๋ง์— ํ•„์š”ํ•˜์ง€ ์•Š๊ณ  ์ผ์‹œ์ ์ด์ง€๋งŒ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•˜๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

actionCreator() {
  ... getState
  ... some logic L1
  ... dispatch({ACTION1})
}

reducer() {
  case ACTION1
    ... some logic L2
    ... x, y result from L2
    ... some logic L3
    ... resulting in new state
    ... return new state
}

๊ฐ์†๊ธฐ์—์„œ ๊ณ„์‚ฐ ๋œ x, y๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” 3 ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์™„๋ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

1) ๊ฐ์†๊ธฐ์—์„œ ์•ก์…˜ ์ƒ์„ฑ๊ธฐ๋กœ ๋กœ์ง์„ ์ด๋™ํ•˜๊ณ  ํ•ซ ๋ฆฌ๋กœ๋“œ์˜ ํž˜์„ ์ค„์ž…๋‹ˆ๋‹ค. Reducer๋Š” ๋ฉ์ฒญํ•œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ”„๋กœ๊ทธ๋žจ์ด๊ฑฐ๋‚˜ ๋…ผ๋ฆฌ L3 ์ด์ƒ์ž…๋‹ˆ๋‹ค.

2) x, y๋ฅผ Redux.state์— ์ €์žฅํ•˜๊ณ  ์ž„์‹œ / ์ผ์‹œ์ ์ธ ๊ฐ’์œผ๋กœ ์˜ค์—ผ์‹œํ‚ค๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์†๊ธฐ์™€ ์•ก์…˜ ์ œ์ž‘์ž ์‚ฌ์ด์˜ ๊ธ€๋กœ๋ฒŒ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ์ฑ„๋„๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ์ƒํƒœ๋ผ๋ฉด ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์ด๋Ÿฐ ๊ฐ€์น˜๊ด€์€ ์•„๋‹™๋‹ˆ๋‹ค. ์•ก์…˜ ์ œ์ž‘์ž๊ฐ€ ๋‹ค์Œ์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

actionCreator() {
  ... getState
  ... some logic L1
  ... dispatch({ACTION1})
  // I assume I get updated state if previous dispatch is sync.
  // If previous dispatch is async it has to be chained properly.
  // If updated state can't be received here after a dispatch
  // then I would think there is a flaw.
  ... getState
  ... asyncOperation(state.x, state.y)
}

3) x, y๋ฅผ ์ƒํƒœ๋กœ ์ €์žฅํ•˜๊ณ  ์ผ๋ถ€ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์†Œํ’ˆ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  componentWillReceiveProps๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ๋ทฐ ๋ ˆ์ด์–ด ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ํ„ฐ๋„๋งํ•˜์—ฌ ์ƒˆ ์ž‘์—… ์ƒ์„ฑ์ž์™€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฒŒ ๋ฌป๋Š”๋‹ค๋ฉด ์ตœ์•…์˜ ์˜ต์…˜์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‚ฌ๋ฐฉ์œผ๋กœ ํผ๋œจ๋ฆฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ธ”๋ผ ๋‹ค๋ฅด
์ผ๋ฐ˜์ ์œผ๋กœ์ด ์ž‘์—…์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ž‘์—…์œผ๋กœ ์••์ถ•๋˜๊ณ  ๊ฐ์†๊ธฐ์— ์˜ํ•ด ์ „๋‹ฌ ๋ฐ ์ ์šฉ๋˜๋Š” ํ•œ ๋น„๋™๊ธฐ๊ฐ€ ์‹œ์ž‘๋˜๋Š” ์œ„์น˜๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์•ก์…˜ ์ƒ์„ฑ ์ž๋‚˜ ์ƒ์ ์—์„œ ๋น„๋™๊ธฐ๋ฅผ ์‹œ์ž‘ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐ”๋‹๋ผ ํ”Œ๋Ÿญ์Šค์™€ ๋™์ผํ•œ ๋…ผ์˜์ž…๋‹ˆ๋‹ค.

Redux๊ฐ€ ์žฌ์ƒ์‹œ ์ด๋Ÿฌํ•œ ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์‹๋ณ„ํ•˜๊ณ  ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ์—์„œ ์ž‘์—… ์ƒ์„ฑ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ผ๋ถ€ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ฆ์ƒ ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์˜ˆ๋Š” ๋‚ด ๊ด€์ ์„ ๋งค์šฐ ์ž˜ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค (์•„๋ž˜ ์ฐธ์กฐ).

์ผ๋ฐ˜ํ™” ๋œ ์ƒํƒœ ์ „ํ™˜ ํ๋ฆ„์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค (FSM ์„ธ๊ณ„์—์„œ) :

  1. ์ด๋ฒคํŠธ ๋„์ฐฉ
  2. ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์ฃผ์–ด์ง€๋ฉด FSM์€ ์ƒˆ๋กœ์šด ๋ชฉํ‘œ ์ƒํƒœ๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
  3. FSM์€ ํ˜„์žฌ ์ƒํƒœ์—์„œ ์ƒˆ ์ƒํƒœ๋กœ ์ „ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค! ๋™์ผํ•œ ์ด๋ฒคํŠธ๋Š” ํ˜„์žฌ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ 3 ๋‹จ๊ณ„์—์„œ ๋‹ค๋ฅธ ์ž‘์—… ์‹œํ€€์Šค (๋˜๋Š” ์ธ์ˆ˜)๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ์•ก์…˜์ด ๋™๊ธฐํ™” ๋  ๋•Œ Flux์—์„œ ์ƒํƒœ ์ „ํ™˜์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๊ฐ์†๊ธฐ / ์ €์žฅ์†Œ๋Š” ์‹ค์ œ๋กœ FSM์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋น„๋™๊ธฐ ์ž‘์—…์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ Flux ์˜ˆ์ œ๋Š” ๋ฐ˜์ „ ๋œ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜๊ฒŒํ•ฉ๋‹ˆ๋‹ค.

  1. AC๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค (ํ˜„์žฌ ์ƒํƒœ์— ๊ด€๊ณ„์—†์ด).
  2. AC๋Š”์ด ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋กœ ์ž‘์—…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. Reducer / Store๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ˜„์žฌ ์ƒํƒœ๋Š” ๋ฌด์‹œ๋˜๊ณ  ๋Œ€์ƒ ์ƒํƒœ๋Š” ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ผ๊ด€๋œ ์ƒํƒœ ์ „ํ™˜ ํ๋ฆ„์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผํ•ฉ๋‹ˆ๋‹ค (AC ํฌํ•จ).

  1. AC๋Š” ์กฐ์น˜๊ฐ€ ์ „๋‹ฌ๋˜๊ธฐ ์ „์— ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  2. AC ํŒŒ๊ฒฌ ์กฐ์น˜
  3. AC๋Š” ์กฐ์น˜ ํ›„ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค.
  4. ์กฐ์น˜ ์ „๊ณผ ํ›„ ์ƒํƒœ๊ฐ€ ์ฃผ์–ด์ง-์ˆ˜ํ–‰ ํ•  ์ž‘์—… (๋˜๋Š” ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ๊ฐ’)์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๋‹จ๊ณ„๊ฐ€ ํ•ญ์ƒ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ข…์ข… ์ผ๋ถ€๋ฅผ ์ƒ๋žต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ ‡๊ฒŒ ํ–‰๋™ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ƒํƒœ ์ „ํ™˜์˜ ์ผ๋ฐ˜ํ™” ๋œ ํ๋ฆ„์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ FSM์˜ ๊ฒฝ๊ณ„๊ฐ€ AC ๋Œ€ ๊ฐ์†๊ธฐ / ์ €์žฅ์†Œ๋กœ ์ด๋™ํ–ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฒฝ๊ณ„๋ฅผ ์ด๋™ํ•˜๋ฉด ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  1. ๋น„๋™๊ธฐ ์ž‘์—…์ด ์ €์žฅ / ๊ฐ์†๊ธฐ์—์žˆ๋Š” ๊ฒฝ์šฐ ๋™์ผํ•œ ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜๋Š” ๋‘ ๊ฐœ์˜ ๋…๋ฆฝ์  ์ธ FSM์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๊ธฐ์กด ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜๋Š” ์ €์žฅ์†Œ / ๊ฐ์†๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ๋งŒํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค.
    ๊ทธ๋Ÿฌ๋‚˜ AC์—์„œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์ €์žฅ์†Œ / ๋ฆฌ๋“€์„œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๋…ผ๋ฆฌ์˜ ๋น„๋™๊ธฐ ๋ถ€๋ถ„์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ธฐ์กด AC๋กœ ์ด๋™ํ•˜์—ฌ ํŽธ์ง‘ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฐ์†๊ธฐ์— ๋Œ€ํ•œ ๋น„๋™๊ธฐ ๋…ผ๋ฆฌ๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด ๋ฉ‹์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    ๊ทธ๋Ÿฌํ•œ ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  2. ๋™๊ธฐํ™” ์ž‘์—…๊ณผ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฝ์šฐ ์•ฑ์˜ ์ œ์–ด ํ๋ฆ„์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋™๊ธฐ ๋™์ž‘์˜ ๊ฒฝ์šฐ ๋ฆฌ๋“€์„œ๊ฐ€ ์ „ํ™˜์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ์˜ ๊ฒฝ์šฐ-AC๋Š”์ด ์ด๋ฒคํŠธ / ๋™์ž‘์— ์˜ํ•ด ์ž ์žฌ์ ์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜์žˆ๋Š” ๋ชจ๋“  ์ „ํ™˜์„ ํšจ๊ณผ์ ์œผ๋กœ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์›น ์•ฑ์˜ ๊ฐ„๋‹จํ•œ ์ƒํƒœ ์š”๊ตฌ ์‚ฌํ•ญ์— ์˜ํ•ด ์ˆจ๊ฒจ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณต์žกํ•œ ์ƒํƒœ ์ €์žฅ ์•ฑ์ด์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์— ํ™•์‹คํžˆ ์ง๋ฉดํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ชจ๋“  ์ข…๋ฅ˜์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒํƒœ ์ „ํ™˜ ๋…ผ๋ฆฌ๊ฐ€ ๋” ์ž˜ ์บก์Šํ™”๋˜๊ณ  FSM์ด AC์™€ ๊ฐ์†๊ธฐ๊ฐ„์— ๋ถ„๋ฆฌ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ฒ˜์Œ๋ถ€ํ„ฐ์ด๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถˆํ–‰ํ•˜๊ฒŒ๋„ ์ƒํƒœ ์ „ํ™˜์˜ "๋ถ€์ž‘์šฉ"๋ถ€๋ถ„์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์ƒํƒœ ์ „ํ™˜์˜ ์ผ๋ถ€์ด๋ฉฐ ๋ณ„๋„์˜ ๋…๋ฆฝ์  ์ธ ๋…ผ๋ฆฌ ๋ถ€๋ถ„์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ (state, action) => (state, sideEffects) ์ด ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค. ์˜ˆ, ๋” ์ด์ƒ "๊ฐ์†Œ"์„œ๋ช…์ด ์•„๋‹™๋‹ˆ๋‹ค. %)ํ•˜์ง€๋งŒ ํ”„๋ ˆ์ž„ ์›Œํฌ์˜ ๋„๋ฉ”์ธ์€ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์ด ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ „ํ™˜์ž…๋‹ˆ๋‹ค.

์•ก์…˜ ์ƒ์„ฑ ์ž๋‚˜ ์ƒ์ ์—์„œ ๋น„๋™๊ธฐ๋ฅผ ์‹œ์ž‘ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐ”๋‹๋ผ ํ”Œ๋Ÿญ์Šค์™€ ๋™์ผํ•œ ๋…ผ์˜์ž…๋‹ˆ๋‹ค.

์˜ˆ, ๊ทธ๋Ÿฌ๋‚˜ Flux๋Š” ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์—์„œ dispatch ()๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํ•œ ์Šคํ† ์–ด์— ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ ๊ฐ–๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ตฌํ˜„์—์„œ ๋น„๋™๊ธฐ๋ฅผ ์œ„ํ•ด AC๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด MVC์˜ ํšŒ์ƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด AC๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ •์‹ ์ ์œผ๋กœ FSM์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ •์‹ ์ ์œผ๋กœ ํŽธ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ธ”๋ผ ๋‹ค๋ฅด

(state, action) => (state, sideEffects)

๊ทธ๋ƒฅ ์ƒ๊ฐ. ์ฆ‰, combineReducers ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ [state, SideEffects] ๋˜๋Š” [state, [SideEffects]]๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋ฆฌ๋“€์„œ์˜ SideEffect๋ฅผ ๊ฒฐํ•ฉํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์›๋ž˜ (์ƒํƒœ, ์กฐ์น˜) => ์ƒํƒœ ๊ฐ์†๊ธฐ ์œ ํ˜•์€ ๊ณ„์† ์ง€์› ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” combineReducer๊ฐ€ ์œ ํ˜•์„ [์ƒํƒœ] ๋˜๋Š” [์ƒํƒœ, []]๋กœ ๊ฐ•์ œ (์ƒํƒœ) ๋ฆฌํ„ดํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ Redux ์–ด๋”˜๊ฐ€์— SideEffect๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ „๋‹ฌํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ์ ์šฉํ•˜๊ณ  SideEffects ๋ชฉ๋ก์„ ์‹คํ–‰ํ•˜๊ณ  ๋””์ŠคํŒจ์น˜ํ•˜๋Š” Store.dispatch ()์—์„œ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋ฉ‹์ง„ ๋์—†๋Š” ์žฌ๊ท€์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š”์ง€ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด ์ˆ˜์ค€์˜ ์–ด๋”˜๊ฐ€์—์„œ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์ง€๋งŒ Store.dispatch๊ฐ€ ์ž‘์—…๊ณผ ํ•จ๊ป˜ SideEffects ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ธ”๋ผ ๋‹ค๋ฅด

์˜ˆ, ๊ทธ๋Ÿฌ๋‚˜ Flux๋Š” ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์—์„œ dispatch ()๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํ•œ ์Šคํ† ์–ด์— ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ ๊ฐ–๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ตฌํ˜„์—์„œ ๋น„๋™๊ธฐ๋ฅผ ์œ„ํ•ด AC๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด MVC์˜ ํšŒ์ƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด AC๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ •์‹ ์ ์œผ๋กœ FSM์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ •์‹ ์ ์œผ๋กœ ํŽธ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ActionCreators๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋Œ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์‚ฌ๊ณ  ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋…ผ๋ฆฌ์˜ ๊ฒฝ์šฐ ๊ฐ์†๊ธฐ์—์„œ ๋‹ค์‹œ AC๋กœ ์ œ์–ด๋ฅผ ๋˜๋Œ๋ ค ์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ฃจํŠธ ์›์ธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿด ํ•„์š” ์—†์–ด์š”. AC๊ฐ€ ๋น„๋™๊ธฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ ์š”์ฒญ ์ฒ˜๋ฆฌ๊ธฐ์™€ ๋น„์Šทํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋‚ด๋ฆฐ ๊ฒฐ์ •์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ์ด ์š”์ฒญ์€ ๋„๋ฉ”์ธ์„ ๊ฐ€๋กœ ์งˆ๋Ÿฌ์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ๋กœ์„œ์˜ ์—ญํ• ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ด์ œ ์œ ์ผํ•œ ์˜ต์…˜์€ ์Šค๋งˆํŠธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ†ตํ•ด ๋…ผ๋ฆฌ๋ฅผ ๋ผ์šฐํŒ…ํ•˜๊ณ  ActionCreators๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UI์— ๋Œ€ํ•œ ์ง์ ‘ ์‘๋‹ต์œผ๋กœ ๋…ผ๋ฆฌ์˜ ์ดˆ๊ธฐ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์ฒซ ๋ฒˆ์งธ ๊ฒฐ์ •์€ Redux.state ๋ฐ / ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋กœ์ปฌ ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋Š” ์Šค๋งˆํŠธ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

๋ฒ”์ฃผ๋ฅผ ์‚ญ์ œํ•˜๊ณ  webapi๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‘๋‹ต์œผ๋กœ ๋‹ค๋ฅธ ํ•ญ๋ชฉ์„ ์ƒˆ๋กœ ๊ณ ์น˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋Š” ์ด์ „ ์˜ˆ์ œ์˜์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •์— ๋”ฐ๋ผ ์„œ๋กœ ๋‹ค๋ฅธ ๊ธฐ์ˆ ์˜ ํ˜ผํ•ฉ์œผ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. AC, ๊ฐ์†๊ธฐ, ์Šค๋งˆํŠธ ๊ตฌ์„ฑ ์š”์†Œ์— ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๊นŒ? ํŒจํ„ด์ด ์–ด๋–ป๊ฒŒ ์ง„ํ™”ํ•˜๋Š”์ง€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์ƒ์ ์—์„œ ๋ฉ€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํฌ์ธํŠธ๋ฅผ ๊ตฌ์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ํƒ€๋‹นํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋ณต์žก์„ฑ์„ ์ƒ๋‹นํžˆ ์ฆ๊ฐ€์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ์Šคํ† ์–ด / ๋ฆฌ๋“€์„œ์—์„œ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ฑฐ๊ธฐ์—์„œ ์‹คํ–‰ํ•˜๊ณ  ๋””์ŠคํŒจ์น˜ํ•˜๊ฑฐ๋‚˜ ์ˆœ์ˆ˜ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ๋ฐ์ดํ„ฐ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋จผ ๊ณณ์—์„œ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ํ•œ ๊ทธ๋‹ค์ง€ ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•กํ„ฐ๋Š” ๋น„์Šทํ•˜๊ฒŒ ๋น„๋™๊ธฐ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‹ค๋ฅธ ์•กํ„ฐ์—๊ฒŒ ๋ฉ”์‹œ์ง€ (์•ก์…˜ ๊ฐ์ฒด)๋ฅผ ๋ณด๋‚ด๊ฑฐ๋‚˜ FSM์—์„œ ๊ณ„์†ํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ์—๊ฒŒ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์กฐ์น˜ ํ•  ์ˆ˜์žˆ๋Š” ๊ฒƒ์ด์—†๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ๋‹ซ์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ž‘์—… ๋ฌธ์„œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์งˆ๋ฌธ์— ๋‹ตํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์ด๋ก ์  ๋…ผ์˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‹คํ–‰ํ•  ์ˆ˜์žˆ๋Š” ์‹ค์ œ ์ฝ”๋“œ ์—†์ด๋Š” ๋‚˜์—๊ฒŒ ๊ฐ€์น˜์žˆ๋Š” ๊ฒƒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ;-)

@gaearon redux๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ ์ค‘ ํ•˜๋‚˜์— API ํ˜ธ์ถœ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•˜๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ (๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” "์‹ค์ œ"์˜ˆ์ œ ์™ธ๋ถ€)?

๋ชจ๋“  ๋ฌธ์„œ์™€์ด ๋ฌธ์ œ๋ฅผ ๋ช‡ ๋ฒˆ ์ฝ์€ ํ›„์—๋„ ์‹ค์ œ ๋ฐฐ์น˜์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ€์ž‘์šฉ์„ ๋ฐฐ์น˜ ํ•  ํŒŒ์ผ์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค https://github.com/rackt/redux/issues/291#issuecomment -123010379 . ์ด ์ด์Šˆ ์Šค๋ ˆ๋“œ์˜ "์˜ฌ๋ฐ”๋ฅธ"์˜ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜์—ญ์— ๋Œ€ํ•œ ์„ค๋ช…์— ๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋ถˆ์ˆœํ•œ ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ์— ๋Œ€ํ•œ ์ค‘์š”ํ•œ ์ƒ๊ฐ์„ ๋ง์”€ ๋“œ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

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

๋‚ด๊ฐ€ ๊ฐœ๋ฐœ์ค‘์ธ ์•ฑ์—๋Š” ์ ์–ด๋„ ๋‘ ๊ฐ€์ง€ ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ์˜จ ์‚ฌ์ดํŠธ Raspberry Pi์—์„œ ์‹คํ–‰๋˜๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํฌํ„ธ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ณ ๊ฐ์ด ์šด์˜ํ•˜๋Š” ๊ณต๊ฐœ ํฌํ„ธ / ํฌํ„ธ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ๋ฒ„์ „์ด์žˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ API๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” ๋ถˆํ™•์‹คํ•˜์ง€๋งŒ ๊ฐ€๋Šฅํ•œ ํ•œ ๊ทธ ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€๋น„ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‚˜์—๊ฒŒ API ํ˜ธ์ถœ์„ ์•ก์…˜ ์ƒ์„ฑ์ž์—๊ฒŒ ๋ถ„์‚ฐ์‹œํ‚ค๋Š” ๊ฐœ๋…์€ ์ƒํƒœ ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•œ ์ค‘์•™ ์ง‘์ค‘์‹ ์ œ์–ด๋ผ๋Š” Redux ๊ฐœ๋…๊ณผ ์™„์ „ํžˆ ๋ฐ˜๋Œ€๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก , API ์š”์ฒญ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋‹ค๋Š” ๋‹จ์ˆœํ•œ ์‚ฌ์‹ค์€ Redux ์Šคํ† ์–ด ์ƒํƒœ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ์ง€๋งŒ, ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ •ํ™•ํ•œ ์ œ์–ด๋ฅผ ์›ํ•˜๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Redux ์ €์žฅ์†Œ / ๊ฐ์†Œ ๊ธฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ œ์–ด๊ฐ€ ๋ถ„์‚ฐ์ด ์•„๋‹Œ ์ค‘์•™ ์ง‘์ค‘ํ™” ๋  ๋•Œ ๊ฐ€์žฅ ์ •๋ฐ€ํ•˜๊ฒŒ ์ œ์–ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ jedwards1211 https://github.com/redux-effects/redux-effects ์— ๊ด€์‹ฌ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ํ™•์ธํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์™€ # 569์—์„œ ๋…ผ์˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon ์ฟจ, ์ง€์  ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์–ด์จŒ๋“  ๋‚ด ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ง€๊ธˆ๊นŒ์ง€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. :)

๋‚˜๋Š” Elm๊ณผ ๊ฐ™์€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค : redux-side-effect . README ๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์„ ์„ค๋ช…ํ•˜๊ณ  ๋Œ€์•ˆ๊ณผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

@gregwebs ๋‚˜๋Š” redux-side-effect ์ข‹์•„ํ•˜์ง€๋งŒ ์Šค์™‘ ๊ฐ€๋Šฅํ•œ ์ œ์–ด ๋กœ์ง๋„ ์–ด์ƒ‰ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์ €์žฅ์†Œ ๊ตฌ์„ฑ์ž๊ฐ€์žˆ์„ ๋•Œ sideEffect ํ•จ์ˆ˜๋ฅผ ๋‚ด ๊ฐ์†๊ธฐ ๋ชจ๋“ˆ๋กœ ๊ฐ€์ ธ ์˜ค๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋นŒ๋“œ์—์„œ ์‚ฌ์šฉํ•  ๋ชจ๋“ˆ.

๊ทธ๋ž˜๋„ ์žฌ๋ฏธ์žˆ๋Š” ํ•ดํ‚น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. state ์ž์ฒด์— sideEffect ๋งŒ ์ €์žฅํ•˜๋ฉด ๊ฐ์†๊ธฐ์—์„œ ์ž๋™์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! : stuck_out_tongue_winking_eye :

https://github.com/rackt/redux/pull/569/ ์™€ ๊ฐ™์€ ๊ฒƒ์€ ๋‚ด๊ฐ€ ์ž‘์—…ํ•˜๋ ค๋Š” ๋ฐฉ์‹์— ์ด์ƒ์ ์— ๊ฐ€๊น์ง€๋งŒ ๋ฌผ๋ก  ํ‘œ์ค€ ๋ถ€ํ’ˆ์ด ์•„๋‹Œ ํ•œ ํ”„๋กœ๋•์…˜ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. API์˜.

์—ฌ๊ธฐ์— ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์•ก์…˜์— sideEffect ํ•จ์ˆ˜๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค. ์•ฝ๊ฐ„ ํ•ดํ‚คํ•˜์ง€๋งŒ ๊ฐ์†๊ธฐ๊ฐ€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ฐ€์žฅ ์ž‘์€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ :

sideEffectMiddleware.js :

export default store => next => action => {
  let sideEffects = [];
  action.sideEffect = callback => sideEffects.push(callback);
  let result = next(action);
  sideEffects.forEach(sideEffect => sideEffect(store));
  return result;
};

๊ฐ„๋‹จํ•œ sideEffect ์ ‘๊ทผ ๋ฐฉ์‹์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€ํ˜•์„ ์‹œ๋„ํ•˜๊ณ  ๋‹ค์‹œ๋ณด๊ณ ํ•˜์‹ญ์‹œ์˜ค.

์œ„์˜ sideEffectMiddleware ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋งํ–ˆ์œผ๋ฉฐ ๊ฒฐ๊ณผ ์ฝ”๋“œ ๊ตฌ์„ฑ์ด ์ •๋ง ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. sideEffect ํ•จ์ˆ˜๋ฅผ ๋‚ด ๋ฆฌ๋“€์„œ๋กœ ๊ฐ€์ ธ์˜ฌ ํ•„์š”๊ฐ€์—†๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. action ๋ฉ๋‹ˆ๋‹ค.

@ jedwards1211 ํŒจํ‚ค์ง€ ๋ฒ„์ „ 2.1.0์—์„œ ์ฝ”๋“œ๋ฅผ actionSideEffectMiddleware ๋กœ ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

@gregwebs ๋ฉ‹์ง€๋‹ค! ์ €๋ฅผ ๊ณต๋™ ์ž‘์—…์ž๋กœ ๋“ฑ๋ก ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@ jedwards1211 ๋‹น์‹ ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ ๋‹น์‹ ์€ ์ ์ ˆํ•œ ์žฌ์ƒ ์ง€์›์„ ์ถ”๊ฐ€ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. :) ๋‚˜๋Š” ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์—์„œ ์•„์ง ๊ทธ๊ฒƒ์„ ์ด์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@gaearon ๊ธฐ๋กํ•˜๊ณ  ์žฌ์ƒ ํ•œ ์•ก์…˜์€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ „ํ˜€ ๊ฑฐ์น˜์ง€ ์•Š๋Š” ๊ฑฐ์ฃ ?

๊ทธ๋“ค์€ ๊ธฐ๋ก ๋  ๋•Œ ์ด๋ฏธ ํ‰๋ฒ”ํ•œ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฏธ๋“ค์›จ์–ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐœ์ž…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@gaearon ํ . ๊ทธ๋ž˜์„œ ์‹ค์ œ๋กœ ๊ทธ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ ํ•ด๋ณธ ์ ์€ ์—†์ง€๋งŒ ... ๋ถ€์ž‘์šฉ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋…น์Œ / ์žฌ์ƒ๋„ ๊นจ๋œจ๋ฆด ๊ฒƒ ๊ฐ™๋„ค์š”? ์˜ˆ๋ฅผ ๋“ค์–ด redux-effects-fetch ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜ ๊ฐ์ฒด FETCH ์ž‘์—…์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ajax ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

function fetchMiddleware ({dispatch, getState}) {
  return next => action =>
    action.type === 'FETCH'
      ? fetch(action.payload.url, action.payload.params).then(checkStatus).then(deserialize, deserialize)
      : next(action)
}

๋ ˆ์ฝ”๋”๊ฐ€ FETCH ์ž‘์—…์˜ steps ์—์„œ [success, failure] ์ฝœ๋ฐฑ์„ ์ •๋ฆฌํ•˜๋ฉด redux-effects ๋ฏธ๋“ค์›จ์–ด๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ ์ž‘์—…์„ ์ „๋‹ฌํ•˜์ง€ ์•Š์ง€๋งŒ ์—ฌ์ „ํžˆ ์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ajax ์š”์ฒญ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์žฌ์ƒํ•ฉ๋‹ˆ๋‹ค.

redux-logger ์™€ ๊ฐ™์€ "์ˆœ์ˆ˜ํ•œ"๋ฏธ๋“ค์›จ์–ด (์ถ”๊ฐ€ ์ž‘์—…์„ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”)๋ฅผ "์ˆœ์ˆ˜ํ•œ"๋ฏธ๋“ค์›จ์–ด (์ž‘์—…์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ)์™€ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆํƒ€๊น๊ฒŒ๋„ redux-effects ๋ฉด๋ฐ€ํžˆ ์กฐ์‚ฌํ•˜์ง€ ์•Š์•„ ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋‹ต๋ณ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๋ ˆ์ฝ”๋”๋Š” ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” ์ž‘์—…์— ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๊นŒ? ๋‚ด ๋ฏธ๋“ค์›จ์–ด์—์„œ devtools๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์›ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ธํ•ธ์„œ ์ปดํฌ์ง€์…˜ ์ฒด์ธ์— devTools() _after_ applyMiddleware ๋ฅผ ๋„ฃ์–ด์•ผํ•˜๋ฏ€๋กœ ์•ก์…˜์— ๋„๋‹ฌ ํ•  ๋•Œ๊นŒ์ง€ ์ถ”๊ฐ€ ํ•ด์„์ด ํ•„์š”์—†๋Š” "์ตœ์ข…"์•ก์…˜์ด๋ฉ๋‹ˆ๋‹ค.

์•„, ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ ํ•œ ํ›„์—๋Š” ์ž‘์—…์—์„œ ํ•„๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์žฌ์ƒ์‹œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ†ตํ•ด ๋˜๋Œ์•„ ๊ฐˆ ๋•Œ ๋ถ€์ž‘์šฉ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์กฐ์ •ํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ๋„๊ตฌ๋กœ ์ž‘์—…ํ•˜์ง€?

๋„ค, ์ข‹์€ ๋ฐฉ๋ฒ• ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊นจ๋‹ฌ์Œ์„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@gaearon @vladar @ jedwards1211 https://github.com/salsita/redux-side-effects์— ๊ด€์‹ฌ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (state, action) => (state, sideEffects) ์˜ ๊ตฌํ˜„์ด์ง€๋งŒ ๋ฆฌ๋“€์„œ๊ฐ€ ํŠœํ”Œ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  (์ด๋ฏธ ๋ฐœ๊ฒฌ ํ•œ ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅ ํ•จ) ํšจ๊ณผ๋ฅผ ์‚ฐ์ถœํ•ฉ๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ณง ๊ทธ๊ฒƒ์„ ๊ฐ€์ง€๊ณ  ๋†€์•˜๊ณ , ํ•ซ ๋ฆฌ๋กœ๋“œ์™€ ๋ฆฌํ”Œ๋ ˆ์ด๋Š” ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ redux ๊ธฐ๋Šฅ์ด ์†์ƒ๋˜์ง€๋Š” ์•Š์•˜์ง€๋งŒ ๊ณ ์œ„ reduxer ์ค‘ ์ผ๋ถ€๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. :)
๋‚˜์—๊ฒŒ ์ด๊ฒƒ์€ ๋กœ์ง์ด ์ฃผ๋กœ ๋ฆฌ๋“€์„œ์— ์žˆ๋„๋กํ•˜์—ฌ ํšจ๊ณผ (ํ˜„์žฌ ์ƒํƒœ์—๋งŒ ์˜์กดํ•˜์ง€ ์•Š๋Š” ์ „ํ™˜ ๋™์ž‘)๋ฅผ ์™ธ๋ถ€ ์„œ๋น„์Šค์— ์œ„์ž„ํ•˜๋Š” ํšจ๊ณผ์ ์ด๊ณ  ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋จธ์‹ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฆฌ๋•์Šค ์Šคํƒ์— ์ •๋ง ์ค‘์š”ํ•œ ์ถ”๊ฐ€๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. Elm ์•„ํ‚คํ…์ฒ˜, ํšจ๊ณผ ๋ฐ ์„œ๋น„์Šค์™€ ๋งค์šฐ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์ ‘๊ทผ๋ฒ•์€ redux-saga ๋กœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๋ฆฌ๋“€์„œ์™€ ๋ถ€์ž‘์šฉ์„ ๋ณ„๋„๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์˜๋ฏธ @minedeljkovic ์ƒ๊ฐ @gaearon

๋‚˜์—๊ฒŒ ์ด๊ฒƒ์€ ๋กœ์ง์ด ์ฃผ๋กœ ๋ฆฌ๋“€์„œ์— ์žˆ๋„๋กํ•˜์—ฌ ํšจ๊ณผ (ํ˜„์žฌ ์ƒํƒœ์—๋งŒ ์˜์กดํ•˜์ง€ ์•Š๋Š” ์ „ํ™˜ ๋™์ž‘)๋ฅผ ์™ธ๋ถ€ ์„œ๋น„์Šค์— ์œ„์ž„ํ•˜๋Š” ํšจ๊ณผ์ ์ด๊ณ  ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋จธ์‹ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฆฌ๋•์Šค ์Šคํƒ์— ์ •๋ง ์ค‘์š”ํ•œ ์ถ”๊ฐ€๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. Elm ์•„ํ‚คํ…์ฒ˜, ํšจ๊ณผ ๋ฐ ์„œ๋น„์Šค์™€ ๋งค์šฐ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

https://github.com/yelouafi/redux-saga/ ๋Š” ๊ธฐ์กด์˜ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋น„ํ•ด ๊ฐ€์žฅ ํฐ ์žฅ์ ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด redux-thunk ์ž‘๋™ ๋ฐฉ์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. .

๋ฐ˜๋ฉด์— https://github.com/salsita/redux-side-effects ๋Š” Elm ์•„ํ‚คํ…์ฒ˜์™€ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, redux-saga ๋ฐ redux-side-effects๋Š” ์ƒ์„ฑ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€์ž‘์šฉ์„ ์„ ์–ธํ•˜๊ณ  sagas์™€ reducer๋ฅผ ๊ฐ๊ฐ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์†๊ธฐ์—์„œ ์„ ํ˜ธํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์ด์œ  :

  1. ํšจ๊ณผ๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜์žˆ๋Š” ํ˜„์žฌ ์ƒํƒœ์— ๋Œ€ํ•œ ๋ช…์‹œ ์  ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค (์ด ๋…ผ์˜ ์ค‘ @vladar ์˜ ์š”์  ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค).
  2. ์ƒˆ๋กœ์šด ๊ฐœ๋…์ด ๋„์ž…๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค (redux-saga์˜ Saga)

https://github.com/rackt/redux/issues/1139#issuecomment -165419770์˜ ๋‚ด ์˜๊ฒฌ์€ redux-saga ํ•ด๊ฒฐ๋˜์ง€ ์•Š๊ณ  ๋ชจ๋ธ์„ ์ˆ˜๋ฝํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ์ „ํžˆ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. Elm ์•„ํ‚คํ…์ฒ˜์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

redux-side-effects์— ๋Œ€ํ•œ ๋‚ด ์š”์ ์„ ๊ฐ•์กฐํ•˜๋ ค๋Š” ๊ฐ„๋‹จํ•œ ์š”์ ์„ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค : https://gist.github.com/minedeljkovic/7347c0b528110889aa50

๋‚˜๋Š” ๋‹จ์ง€ "์‹ค์ œ ์„ธ๊ณ„"๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ •์˜ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ์ด ๋…ผ์˜์˜ ๋ช‡ ๊ฐ€์ง€ ์š”์ ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

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

์•„ํ‚คํ…์ฒ˜ ์ œ์•ฝ :

  1. CountrySelection ๊ธฐ๋Šฅ์€ ๋ชจ๋“ˆ ์‹์ด์–ด์•ผํ•ฉ๋‹ˆ๋‹ค ( redux ducks ์˜ ์ •์‹ ). ๋”ฐ๋ผ์„œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์—์„œ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์˜ˆ : ์ƒ์‚ฐ ๊ตญ๊ฐ€๋ฅผ ์ž…๋ ฅํ•ด์•ผํ•˜๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ "์ œํ’ˆ ๊ด€๋ฆฌ"๋ถ€๋ถ„์—์„œ๋„).
  2. CountrySelection์˜ ์ƒํƒœ ์Šฌ๋ผ์ด์Šค๋Š” ์ „์—ญ (redux ์ƒํƒœ์˜ ๋ฃจํŠธ์— ์žˆ์Œ)์œผ๋กœ ๊ฐ„์ฃผ๋˜์–ด์„œ๋Š” ์•ˆ๋˜์ง€๋งŒ์ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ชจ๋“ˆ (๋ฐ ํ•ด๋‹น ๋ชจ๋“ˆ์— ์˜ํ•ด ์ œ์–ด ๋จ)์— ๋Œ€ํ•ด ๋กœ์ปฌ์ด์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  3. ์ด ๊ธฐ๋Šฅ์˜ ํ•ต์‹ฌ ๋กœ์ง์€ ๊ฐ€๋Šฅํ•œ ํ•œ ์ ์€ ์›€์ง์ด๋Š” ๋ถ€๋ถ„์„ ํฌํ•จํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค (๋‚ด ์š”์ ์—์„œ์ด ํ•ต์‹ฌ ๋กœ์ง์€ ๊ฐ์†๊ธฐ์—์„œ๋งŒ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค (๊ทธ๋ฆฌ๊ณ  ๋กœ์ง์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„ ๋งŒ). ๋ชจ๋“  redux ๊ตฌ๋™ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ํ•ด์•ผํ•˜๋ฏ€๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์‚ฌ์†Œํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜ :). ๊ทธ๋“ค์˜ ์œ ์ผํ•œ ์ฑ…์ž„์€ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์กฐ์น˜๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์ด ๋Œ€ํ™”์™€ ๊ด€๋ จํ•˜์—ฌ ์š”์ ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ countrySelection ๊ฐ์†๊ธฐ๊ฐ€ CONFIRM_SELECTION ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์— ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon , ๋‚˜๋Š” ํ‘œ์ค€ redux์— ์ถ”๊ฐ€ ๋œ redux-side-effects๊ฐ€ constratints๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๋‚ด ์ง„์ˆ ์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์˜๊ฒฌ์„ ๋Œ€๋ถ€๋ถ„ ํ‰๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ๊ตฌํ˜„์„์œ„ํ•œ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ ์•„์ด๋””์–ด (redux-side-effects๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  redux-saga, redux-thunk ๋˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉ)๋„ ๋งค์šฐ ์ ์ ˆํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@ tomkis1 , ๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ๊ท€ํ•˜์˜ ์˜๊ฒฌ์„

(์ด ์š”์  https://gist.github.com/minedeljkovic/9d4495c7ac5203def688์—๋Š” ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ๊ตฌํ˜„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ globalActions๋Š” ํ”ผํ•ฉ๋‹ˆ๋‹ค.์ด ์ฃผ์ œ์—๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€์ด ํŒจํ„ด์— ๋Œ€ํ•ด ์˜๊ฒฌ์„ ๋งํ•˜๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.)

@minedeljkovic ์š”์ ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์˜ ์˜ˆ์—์„œ ํ•˜๋‚˜์˜ ๊ฐœ๋…์  ๋ฌธ์ œ๋ฅผ ๋ด…๋‹ˆ๋‹ค. redux-side-effects ์€ ๋ถ€์ž‘์šฉ์—๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ท€ํ•˜์˜ ์˜ˆ์—๋Š” ๋ถ€์ž‘์šฉ์ด ์—†์ง€๋งŒ ์žฅ๊ธฐ์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๊ฑฐ๋ž˜๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ redux-saga ๊ฐ€ ํ›จ์”ฌ ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. @slorber ์™€ @yelouafi ๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ๊ฒƒ์„

์ฆ‰, ์ €์—๊ฒŒ ๊ฐ€์žฅ ์šฐ๋ ค๋˜๋Š” ๋ฌธ์ œ๋Š” ๋ฆฌ๋“€์„œ (https://github.com/salsita/redux-side-effects/pull/9#issuecomment-165475991) ๋‚ด์—์„œ ์ƒˆ๋กœ์šด ์ž‘์—…์˜ ๋™๊ธฐ์‹ dispatching ์ž…๋‹ˆ๋‹ค.

yield dispatch => dispatch({type: COUNTRY_SELECTION_SUCCESS, payload: state.selectedCountryId});

@slorber ๋Š” "๋น„์ฆˆ๋‹ˆ์Šค ๋ถ€์ž‘์šฉ"์ด๋ผ๋Š” ์šฉ์–ด์™€ ํ•จ๊ป˜ ์™”์œผ๋ฉฐ ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. redux-saga ์€์ด ํŠน์ • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋น›์„ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

@mindjuice ์ €๋Š” ๊ท€ํ•˜์˜ ์˜ˆ์ œ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜์ง€๋Š” ๋ชปํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์— ์ค€ ์˜จ ๋ณด๋”ฉ ์˜ˆ์ œ๊ฐ€ ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค : https://github.com/paldepind/functional-frontend-architecture/issues/20#issuecomment -162822909

saga ํŒจํ„ด์€ ๋˜ํ•œ ์ผ๋ถ€ ์•”์‹œ์ ์ธ ๊ฒƒ์„ ๋ช…์‹œ ์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์ž‘์—…์„ ์‹คํ–‰ํ•˜์—ฌ ๋ฐœ์ƒํ•œ ์ผ์„ ์„ค๋ช…ํ•˜๊ณ  (๋‚˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๊ณผ๊ฑฐ ์‹œ์ œ ์—ฌ์•ผํ•˜๋ฏ€๋กœ ์ด๋ฒคํŠธ๋ฅผ ์„ ํ˜ธ ํ•จ) ์ผ๋ถ€ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์ด ์‹œ์ž‘๋˜๊ณ  UI๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ ์˜ค๋ฅ˜ ํ‘œ์‹œ๋Š” ์•”์‹œ ์ ์ž…๋‹ˆ๋‹ค. ๋ฌด์šฉ๋‹ด์„ ํ†ตํ•ด ํ™•์ธ์‹œ ๊ตญ๊ฐ€๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ "NO_COUNTRY_SELECTED_ERROR_DISPLAYED"๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ์ž‘์—…์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์™„์ „ํžˆ ๋ช…์‹œ์ ์ธ ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์‚ฌ๊ฐ€๋ฅผ ์˜ค๋ฆฌ ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ์ง€์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด duck1๊ณผ duck2๊ฐ€ ์žˆ๊ณ  ๊ฐ๊ฐ์— ๋Œ€ํ•œ ๋กœ์ปฌ ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๋งˆ๋ฆฌ์˜ ์˜ค๋ฆฌ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์•„์ด๋””์–ด๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์œผ๋ฉด (ํ•œ ๋งˆ๋ฆฌ์˜ ์˜ค๋ฆฌ๊ฐ€ ๋‘ ๋ฒˆ์งธ ์˜ค๋ฆฌ์˜ ์ž‘์—… ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค) ๋ฌด์Šจ ์ผ์ด ์ผ์–ด ๋‚ฌ๋Š”์ง€ ์„ค๋ช…ํ•˜๋„๋ก ํ•œ ๋‹ค์Œ ๋‘ ์˜ค๋ฆฌ ์‚ฌ์ด์— ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ์—ฐ๊ฒฐํ•˜๋Š” Saga๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฆฌ 2 ๋งˆ๋ฆฌ.

Sooooo, ๊ทธ๊ฒƒ์€ ์—„์ฒญ๋‚˜๊ฒŒ ๊ธด ์Šค๋ ˆ๋“œ์ด๋ฉฐ ์•„์ง ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋น„๋™๊ธฐ action() ์žˆ๊ณ  ์ฝ”๋“œ๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ฑฐ๋‚˜ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•ด์•ผํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค.

// the action call
action().then(dispatch(SUCCESS)).catch(dispatch(FAILURE))

// the reducer
case SUCCESS:
    state.succeeded = true
    alert('Success')

case FAILURE:
    state.succeeded = false
    alert('Failure')

๊ทธ๋Ÿฌ๋‚˜ ์ด์ œ ๊ฐ์†๊ธฐ์— "๋ถ€์ž‘์šฉ"์ด ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Redux ๋ฐฉ์‹์ด ์•„๋‹™๋‹ˆ๋‹ค (๊ทธ๊ฒŒ ๋ฌด์Šจ ๋œป์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค).
๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์€์ด alert() ๊ฐ์†๊ธฐ์—์„œ ์–ด๋”˜๊ฐ€๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ด๋”˜๊ฐ€์— action ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด์ œ ๋‚ด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// the reducer
case SUCCESS:
    state.succeeded = true

case FAILURE:
    state.succeeded = false

// the React component
on_click: function()
{
    action().then
    ({
        dispatch(SUCCESS)

        alert('Success')
        // do something else. maybe call another action
    })
    .catch
    ({
        dispatch(FAILURE)

        alert('Failure')
        // do something else. maybe call another action
    })
}

์ด์ œ ์ด๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๊นŒ?
์•„๋‹ˆ๋ฉด ๋” ์กฐ์‚ฌํ•˜๊ณ  ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

Redux๋Š” ์ „ํ˜€ ๊ฐ„๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์•ฑ์˜ ๊ฒฝ์šฐ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ํ‘œ์ค€ ์˜ˆ์ œ๋กœ ์ƒ˜ํ”Œ ์‹ค์ œ ์•ฑ ์ €์žฅ์†Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

@ halt-hammerzeit Redux ์ž์ฒด๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋‹จํŽธํ™”๋Š” Redux๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฆฌ๋“€์„œ์˜ ๋ถ€์ž‘์šฉ์„ ํ†ตํ•ฉ / ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์š”๊ตฌ ๋˜๋Š” ์˜๊ฒฌ์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‹จํŽธํ™”๋Š” Redux๋กœ ์›ํ•˜๋Š”๋Œ€๋กœ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋‹ค๋Š” ์‚ฌ์‹ค์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ถ€์ž‘์šฉ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋กค๋งํ•˜๋Š” ๋ฐ ์•ฝ 10 ์ค„์˜ ์ฝ”๋“œ ๋งŒ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ž์œ ๋ฅผ ๋ฐ›์•„๋“ค์ด๊ณ  "์˜ฌ๋ฐ”๋ฅธ"๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

@ jedwards1211 "Redux ์ž์ฒด"๋Š” ๊ฐ€์น˜ ๋‚˜ ์˜๋ฏธ๊ฐ€ ์—†์œผ๋ฉฐ Flux ๊ฐœ๋ฐœ์ž์˜ ์ผ์ƒ์ ์ธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ์ฃผ ๋ชฉ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ AJAX, ์•„๋ฆ„๋‹ค์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐ ๊ธฐํƒ€ ๋ชจ๋“  _ ํ‰๋ฒ”ํ•˜๊ณ  ๊ธฐ๋Œ€๋˜๋Š” _ ๊ฒƒ๋“ค์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

@ halt-hammerzeit ๊ฑฐ๊ธฐ์— ์š”์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Redux๋Š” ํ™•์‹คํžˆ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์ด ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋™์˜ํ•˜๋„๋ก ์˜๋„ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฏ€๋กœ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์ด ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋™์˜ํ•˜์ง€ ์•Š์€ ๊ฒƒ์€ ๋ถ€๋„๋Ÿฌ์šด ์ผ์ž…๋‹ˆ๋‹ค.

์ €์žฅ์†Œ์—์„œ "examples"ํด๋”๋ฅผ ๋ณด์…จ์Šต๋‹ˆ๊นŒ?

๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ถŒ์žฅ ์‚ฌํ•ญ์€ ๋ชจ๋“  ์˜ˆ์—์„œ์™€ ๊ฐ™์ด Redux ์™ธ๋ถ€ ๋˜๋Š” ์•ก์…˜ ์ œ์ž‘์ž ๋‚ด๋ถ€์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„ค, ์•Œ์•„์š” ... ๋‚ด ๋ง์€์ด ์Šค๋ ˆ๋“œ๊ฐ€ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ (์ ์–ด๋„ ์—ฌ๊ธฐ ์‚ฌ๋žŒ๋“ค ์‚ฌ์ด์—์„œ) ํ•ฉ์˜์˜ ๋ถ€์กฑ์„ ์„ค๋ช…ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

^ ๊ทธ๊ฐ€ ๋งํ•œ ๊ฒƒ.

๋‚˜๋Š” ๋ชจ๋“  ์œ„๋Œ€ํ•œ ๋งˆ์Œ์ด ํ•˜๋‚˜์˜ ์˜๋กœ์šด ํ•ด๊ฒฐ์ฑ…์— ๋™์˜ํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค
9000 ๊ฐœ์˜ ํ™”๋ฉด์„ ์ฝ์„ ํ•„์š”๊ฐ€ ์—†๋„๋ก ๋Œ์— ์ƒˆ๊ฒจ์„œ
์‹ค

2016 ๋…„ 1 ์›” 7 ์ผ ๋ชฉ์š”์ผ์— Andy Edwards [email protected] ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

์˜ˆ, ์•Œ์•„์š” ... ๋‚ด๊ฐ€ ๋งํ•˜๊ณ ์žํ•˜๋Š” ๊ฒƒ์€์ด ์Šค๋ ˆ๋“œ๊ฐ€
์ธก๋ฉด์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ•ฉ์˜ (์ ์–ด๋„ ์—ฌ๊ธฐ ์‚ฌ๋žŒ๋“ค ์‚ฌ์ด์—์„œ)
ํšจ๊ณผ.

โ€”
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/rackt/redux/issues/291#issuecomment -169751432.

๊ทธ๋ž˜์„œ, ํ˜„์žฌ ํ•ฉ์˜ ๋œ ํ•ด๊ฒฐ์ฑ…์€ ๋ชจ๋“  ๊ฒƒ์„ ํ–‰๋™์œผ๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ œ์ž‘์ž. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‹œ๋„ํ•ด๋ณด๊ณ  ๊ฒฐํ•จ์ด ๋ฐœ๊ฒฌ๋˜๋ฉด
์—ฌ๊ธฐ์— ๋‹ค์‹œ ๊ฒŒ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

2016 ๋…„ 1 ์›” 7 ์ผ ๋ชฉ์š”์ผ์— ะะธะบะพะปะฐะน ะšัƒั‡ัƒะผะพะฒ [email protected] ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

^ ๊ทธ๊ฐ€ ๋งํ•œ ๊ฒƒ.

๋‚˜๋Š” ๋ชจ๋“  ์œ„๋Œ€ํ•œ ๋งˆ์Œ์ด ํ•˜๋‚˜์˜ ์˜๋กœ์šด ํ•ด๊ฒฐ์ฑ…์— ๋™์˜ํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค
9000 ๊ฐœ์˜ ํ™”๋ฉด์„ ์ฝ์„ ํ•„์š”๊ฐ€ ์—†๋„๋ก ๋Œ์— ์ƒˆ๊ฒจ์„œ
์‹ค

2016 ๋…„ 1 ์›” 7 ์ผ ๋ชฉ์š”์ผ, Andy Edwards < [email protected]
<_e i = "16">

์˜ˆ, ์•Œ์•„์š” ... ๋‚ด๊ฐ€ ๋งํ•˜๊ณ ์žํ•˜๋Š” ๊ฒƒ์€์ด ์Šค๋ ˆ๋“œ๊ฐ€
์ธก๋ฉด์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ•ฉ์˜ (์ ์–ด๋„ ์—ฌ๊ธฐ ์‚ฌ๋žŒ๋“ค ์‚ฌ์ด์—์„œ)
ํšจ๊ณผ.

โ€”
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/rackt/redux/issues/291#issuecomment -169751432.

Redux ์‚ฌ์šฉ์ž์˜ 1 %๊ฐ€ ๋ถ€์ž‘์šฉ์— ๋Œ€ํ•ด ๋” ๊ฐ•๋ ฅํ•˜๊ณ  ์ˆœ์ˆ˜ํ•˜๋ฉฐ ์„ ์–ธ์ ์ธ ์†”๋ฃจ์…˜์„ ์ฐพ๊ณ  ์‹ถ์–ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์™€ ์œ ์‚ฌํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ธ์ƒ์„๋ฐ›์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์นจ๋ฌตํ•˜๋Š” ๋Œ€๋‹ค์ˆ˜๋Š” ์ƒ๊ฐ๊ณผ ์•ฝ์†์„ ์‚ฌ์šฉํ•˜๋ฉฐ ๋Œ€๋ถ€๋ถ„์ด ์ ‘๊ทผ ๋ฐฉ์‹์— ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ๊ธฐ์ˆ ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹จ์ ๊ณผ ์žฅ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ๋…ผ๋ฆฌ๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ Redux๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋Œ€์‹  Rx๋ฅผ ํƒ์ƒ‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Redux ํŒจํ„ด์€ Rx์—์„œ ์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•Œ์•˜์–ด ๊ณ ๋งˆ์›Œ

2016 ๋…„ 1 ์›” 7 ์ผ ๋ชฉ์š”์ผ์— Dan Abramov [email protected] ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

Redux ์‚ฌ์šฉ์ž์˜ 1 %๊ฐ€ ์ฐพ๊ณ  ์‹ถ์–ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์™€ ์œ ์‚ฌํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
๋ถ€์ž‘์šฉ์— ๋Œ€ํ•œ๋ณด๋‹ค ๊ฐ•๋ ฅํ•˜๊ณ  ์ˆœ์ˆ˜ํ•˜๋ฉฐ ์„ ์–ธ์ ์ธ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ์ œ๋ฐœ ํ•˜์ง€๋งˆ
์•„๋ฌด๋„ ๋™์˜ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ธ์ƒ์„๋ฐ›์Šต๋‹ˆ๋‹ค. ์นจ๋ฌตํ•˜๋Š” ๋Œ€๋‹ค์ˆ˜๋Š”
์ƒ๊ฐํ•˜๊ณ  ์•ฝ์†ํ•˜๋ฉฐ ๋Œ€๋ถ€๋ถ„์ด ์ ‘๊ทผ ๋ฐฉ์‹์— ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์–ด๋–ค
๊ธฐ์ˆ ์—๋Š” ๋‹จ์ ๊ณผ ์žฅ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ๋…ผ๋ฆฌ๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ
Redux๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋Œ€์‹  Rx๋ฅผ ํƒ์ƒ‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Redux ํŒจํ„ด์€
Rx์—์„œ ์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ€”
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/rackt/redux/issues/291#issuecomment -169761410.

@gaearon ๋„ค, ๋งž์•„์š”. ๊ทธ๋ฆฌ๊ณ  Redux๊ฐ€ ์šฐ๋ฆฌ์˜ ๋‹ค์–‘ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋ชจ๋‘ ์ˆ˜์šฉ ํ•  ์ˆ˜์žˆ์„๋งŒํผ ์œ ์—ฐํ•˜๋‹ค๋Š” ์ ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

๋‚ด๊ฐ€ REDUX-์‚ฌ๊ฐ€ REDUX-์ฝํฌ๋ณด๋‹ค ๋” ์ข‹์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์ด์œ ๋ฅผ ์„ค๋ช… ๊ณณ @ ์ค‘๋‹จ-hammerzeit ์—ฌ๊ธฐ์— ๋‚ด ๋Œ€๋‹ต์„ ์‚ดํŽด : http://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for- async-flow-in-redux / 34599594

@gaearon ๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ , stackoverflow์— ๋Œ€ํ•œ ๋‹ต๋ณ€์€ ๋ฌธ์„œ์™€ ๋™์ผํ•œ ๊ฒฐํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค-๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค
http://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux/34599594#34599594
์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ AJAX๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ ์˜ค๋Š” ๊ฒƒ ์ด์ƒ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์กฐ์น˜ ํ˜ธ์ถœ์˜ ์ถœ๋ ฅ์— ๋”ฐ๋ผ ์ผ๋ถ€ ์กฐ์น˜๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
๊ท€ํ•˜์˜ ์กฐ์–ธ์€ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ dispatch ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ๋‚ด ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž‘์—… ์™„๋ฃŒ์‹œ alert() ์›ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ๋ฉ๋‹ˆ๊นŒ?
๊ทธ thunk ๋Š” ๋„์›€์ด๋˜์ง€ ์•Š์ง€๋งŒ ์•ฝ์†์€ ๋„์›€์ด๋ฉ๋‹ˆ๋‹ค.
์ €๋Š” ํ˜„์žฌ ๊ฐ„๋‹จํ•œ ์•ฝ์†์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ทธ๋ ‡๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” redux-saga ๋Œ€ํ•œ ์ธ์ ‘ํ•œ ์˜๊ฒฌ์„ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์ด ๋ฌด์—‡์„ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” monads ๋ณ„๋กœ ๊ด€์‹ฌ์ด์—†๊ณ , thunk ๊ฐ€ ๋ญ”์ง€ ์•„์ง๋„ ๋ชจ๋ฅด๊ฒ ๊ณ , ๊ทธ ์ด์ƒํ•œ ๋‹จ์–ด๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๋Š” React ์ปดํฌ๋„ŒํŠธ์—์„œ Promise๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ฝํฌ์—์„œ ์•ฝ์†์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@gaearon ๋„ค, ๊ทธ๊ฒŒ ์ œ๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค : on_click() { dispatch(load_stuff()).then(show_modal('done')) }
๊ทธ๋ ‡๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•„์ง๋„ ๋ญ”๊ฐ€ ๋น ์ง„ ๊ฒƒ ๊ฐ™์•„์š”.
redux-thunk์˜ README๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.
"์ปดํฌ์ง€์…˜"์„น์…˜์—์„œ ์ฝํฌ ์•ก์…˜ ์ƒ์„ฑ์ž๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

@gaearon ๋„ค, ์ •ํ™•ํžˆ ์ œ๊ฐ€ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค.

store.dispatch(
  makeASandwichWithSecretSauce('My wife')
).then(() => {
  console.log('Done!');
});

์œ„์—์„œ ์ผ๋˜ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค.

on_click()
{
    dispatch(load_stuff())
        .then(() => show_modal('done'))
        .catch(() => show_error('not done'))
}

README ์„น์…˜์€ ์ž˜ ์ž‘์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ, ๋‚ด ๋ง์ด ์•„๋‹ˆ์•ผ. makeSandwichesForEverybody ์‚ดํŽด๋ณด์„ธ์š”. ๋‹ค๋ฅธ ์ฝํฌ ์•ก์…˜ ์ œ์ž‘์ž๋ฅผ ๋ถ€๋ฅด๋Š” ์ฝํฌ ์•ก์…˜ ์ œ์ž‘์ž์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ปดํฌ๋„ŒํŠธ์— ๋ชจ๋“  ๊ฒƒ์„ ๋„ฃ์„ ํ•„์š”๊ฐ€์—†๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€์ด ์ €์žฅ์†Œ์˜ async ์˜ˆ์ œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

@gaearon ํ•˜์ง€๋งŒ ๋‚ด ๋ฉ‹์ง„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฝ”๋“œ๋ฅผ ์•ก์…˜ ์ œ์ž‘์ž์—๊ฒŒ ๋„ฃ๋Š” ๊ฒƒ์€ ์ ์ ˆํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
์ด ์˜ˆ๋ฅผ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

button_on_click()
{
    this.props.dispatch(load_stuff())
        .then(() =>
        {
                const modal = ReactDOM.getDOMNode(this.refs.modal)
                jQuery(modal).fancy_animation(1200 /* ms */)
                setTimeout(() => jQuery.animate(modal, { background: 'red' }), 1500 /* ms */)
        })
        .catch(() =>
        {
                alert('Failed to bypass the root mainframe protocol to override the function call on the hyperthread's secondary firewall')
        })
}

์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋‹ค์‹œ ์ž‘์„ฑ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@ halt-hammerzeit ๋‹น์‹ ์€ actionCreator๊ฐ€ ํ”„๋ผ ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋กํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ์ปฌ ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ”ผ๋„ˆ ๋“ฑ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ณต์žกํ•œ ํƒ€์ด๋จธ๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ redux-saga๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌ๋™ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค : http://jaysoo.ca/2016/01/03/managing-processes-in-redux-using-sagas/

์•„,์ด ๊ฒฝ์šฐ ๊ตฌ์„ฑ ์š”์†Œ์— ๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
(์ฐธ๊ณ  : ์ผ๋ฐ˜์ ์œผ๋กœ React์—์„œ๋Š” jQuery๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ช…๋ น ์ ์œผ๋กœ ๋ชจ๋‹ฌ์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์„ ์–ธ์  ๋ชจ๋ธ์„ ๋ชจ๋“  ๊ฒƒ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค.ํ•˜์ง€๋งŒ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.)

@slorber ์˜ˆ, ์ €๋Š” ์ด๋ฏธ "thunks"(๋˜๋Š” ๋‹น์‹ ์ด ๋ถ€๋ฅด๋Š” ๋ชจ๋“  ๊ฒƒ, ์Œ,์ด ์ด์ƒํ•œ ๋‹จ์–ด๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Œ)์—์„œ ์•ฝ์†๊ณผ ๋ฌผ๊ฑด์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์Šคํ”ผ๋„ˆ ๋“ฑ์„ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ โ€‹โ€‹์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon ์ข‹์•„, ๋‚ด๊ฐ€ ์žก์•˜๋‹ค. ์ด์ƒ์ ์ธ ๊ธฐ๊ณ„ ์„ธ๊ณ„์—์„œ๋Š” ๋ฌผ๋ก  ์„ ์–ธ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ ๋‚ด๋ถ€์— ๋จธ๋ฌผ ์ˆ˜ ์žˆ์ง€๋งŒ ํ˜„์‹ค์€ ๊ธฐ๊ณ„์˜ ๊ด€์ ์—์„œ ๋น„ํ•ฉ๋ฆฌ์ ์ธ ์š”๊ตฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์€ ์ˆœ์ˆ˜ํ•œ 0๊ณผ 1๋กœ ์ž‘๋™ํ•˜๋Š” ๋น„์ด์„ฑ์  ์ธ ์กด์žฌ์ด๋ฉฐ ๋น„ํ•ฉ๋ฆฌ์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ์˜ ์•„๋ฆ„๋‹ค์›€๊ณผ ์ˆœ์ˆ˜์„ฑ์„ ์†์ƒ์‹œ์ผœ์•ผํ•ฉ๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์˜ ์ง€์›์— ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์˜์‹ฌ์€ ์ด์ œ ํ•ด๊ฒฐ ๋œ ๊ฒƒ ๊ฐ™๋‹ค.

๊ด€๋ จ ์ƒˆ ํ† ๋ก  : https://github.com/reactjs/redux/issues/1528

@gaearon ๋งค์šฐ ๋ฉ‹์ง„ ์„ค๋ช…! : ํŠธ๋กœํ”ผ : ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค : +1 :

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰