Redux: ์ตœ๊ณ ์˜ ๋น„๋™๊ธฐ ์„œ๋ฒ„ ์ธก ๋กœ๋”ฉ ๊ธฐ์ˆ ์€?

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

์šฐ์„  ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์—ฌ๋Ÿฌ๋ถ„์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ํŒจํ„ด์ด ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ๐Ÿ‘๐Ÿ‘

redux๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ isomorphic ์•ฑ์„ ๋นŒ๋“œํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— ๋‚ด ์ƒ์ ์ด (์„œ๋ฒ„์—์„œ) ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๋ฉด ์ง€๊ธˆ๊นŒ์ง€๋Š” ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ๋กœ๋“œ๊ฐ€ ์ƒ์  ์ž์ฒด์—์„œ ๋ฐœ์ƒํ•ด์•ผ ํ•˜์ง€๋งŒ dispatch(userActions.load()) ํ˜ธ์ถœํ•˜๋ฉด ์ƒ์ ์ด ์ƒˆ ์ƒํƒœ(์˜ˆ: return { ...state, loading: true }; )๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์•ฝ์†์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. dispatch() ๋Š” ์–ด๋–ค ์ด์œ ๋กœ ์ „๋‹ฌ๋œ ์ž‘์—…์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ •๋ง๋กœ ๊ฐ™์€ ๊ฒƒ์„ ์›ํ•ฉ๋‹ˆ๋‹ค ...

dispatch(someAsyncAction, successAction, failureAction) => Promise

...๋‹ค๋ฅธ ๋‘ ์ž‘์—… ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ „๋‹ฌ๋  ๋•Œ๊นŒ์ง€ ์•ฝ์†์ด ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ.

๊ทธ๊ฒƒ์ด ๋ฏธ๋“ค์›จ์–ด ํŒจํ„ด์œผ๋กœ ํ™œ์„ฑํ™”๋  ์ˆ˜ ์žˆ๋Š” ์ข…๋ฅ˜์˜ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ์™„์ „ํžˆ ๊ธฐ๋ณธ์—์„œ ๋ฒ—์–ด๋‚˜ ์žˆ๊ณ  ์ด๋ฏธ ์ด๊ฒƒ์„ ํ•  ์ˆ˜์žˆ๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๊ฐ์‚ฌ ํ•ด์š”.

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

// Middleware
export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, types, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    const [REQUEST, SUCCESS, FAILURE] = types;
    next({ ...rest, type: REQUEST });
    return promise.then(
      (result) => next({ ...rest, result, type: SUCCESS }),
      (error) => next({ ...rest, error, type: FAILURE })
    );
  };
}

// Usage
function doSomethingAsync(userId) {
  return {
    types: [SOMETHING_REQUEST, SOMETHING_SUCCESS, SOMETHING_FAILURE],
    promise: requestSomething(userId),
    userId
  };
}

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

ํ—ค์ด, ๊ณ ๋งˆ์›Œ!

์ด์ƒ์ ์œผ๋กœ๋Š” ๋งค์žฅ ์ž์ฒด์—์„œ ๋กœ๋”ฉ์ด ์ด๋ฃจ์–ด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Redux๋Š” Stores๊ฐ€ ์™„์ „ํžˆ ๋™๊ธฐํ™”๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์€ ๋Œ€์‹  ์•ก์…˜ ์ƒ์„ฑ์ž์—์„œ ๋ฐœ์ƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ฝํฌ ๋ฏธ๋“ค์›จ์–ด๋กœ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  _์ƒ๊ฐ_ํ•ฉ๋‹ˆ๋‹ค. ์•ก์…˜ ์ƒ์„ฑ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export function doSomethingAsync() {
  return (dispatch) => {
    dispatch({ type: SOMETHING_STARTED });

    return requestSomething().then(
      (result) =>  dispatch({ type: SOMETHING_COMPLETED, result }),
      (error) =>  dispatch({ type: SOMETHING_FAILED, error })
    );
  };
}

์Šคํ† ์–ด์—์„œ ์‹ค์ œ(์„ธ๋ถ€์ ์ธ) ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ƒ์šฉ๊ตฌ๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ •์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ฒœ์žฌ! ๋‚˜๋Š” ๋‚ด๊ฐ€ ๋ช…๋ฐฑํ•œ ๊ฒƒ์„ ๊ฐ„๊ณผํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๋‚˜๋Š” _doing_๊ณผ _storing_์˜ ๋ถ„๋ฆฌ๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฏธ ์™„์„ฑ๋œ ์ƒํƒœ์ด์ง€๋งŒ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์„ฑ์žฅํ•˜๋Š” ๊ฒƒ์„ ์ง€์ผœ๋ณด๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑด๋ฐฐ @gaearon!

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ •์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

๊ธฐ๋ณธ๊ฐ’ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—… ์ƒ์„ฑ๊ธฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์ด

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }

์˜ค, ๊ทธ๊ฒƒ๋„ ์ข‹๊ตฐ์š”. ๊ทธ๋ฆฌ๊ณ  ์ œ๊ฐ€ ์›๋ž˜ ์งˆ๋ฌธ์„ ํ•  ๋•Œ ์—ผ๋‘์— ๋‘์—ˆ๋˜ ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์Šต๋‹ˆ๋‹ค. ์ƒ์  ๋‚ด๋ถ€์˜ readyState ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด if ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋Œ€๊ฐ€๋กœ ์•ก์…˜ ์ƒ์ˆ˜์˜ ์ˆ˜๋ฅผ ์ค„์ด๋Š” ์ ˆ์ถฉ์•ˆ์ด ๋งˆ์Œ์— ๋“œ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ addtional ๊ฐ€์ง„ ์„ ํ˜ธ ํ•  ์ƒ๊ฐ _SUCCESS ๋ฐ _FAILURE ๋‹จ์ง€ ํผํŒ… ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ์ž‘์—…์˜ ๋ฒ„์ „์„ if , ์•ˆ์ชฝ case .

๊ทธ๋ž˜๋„ ๊ณ ๋งˆ์›Œ.

๋„ค, ๊ทธ๊ฒƒ์€ ์ „์ ์œผ๋กœ ๊ท€ํ•˜์˜ ์ทจํ–ฅ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. types: { request: ..., success: ..., failure: ... } ๋ฅผ ์ž‘์—…์œผ๋กœ ๋ฐ”๊พธ๋Š” ์œ ์‚ฌํ•œ ๋ฒ„์ „์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋ฒ ์ดํ‚นํ•˜๋Š” ๋Œ€์‹  ๋ฏธ๋“ค์›จ์–ด๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‚ฌ๋žŒ์€ ์ด๋Ÿฌํ•œ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์ž์‹ ๋งŒ์˜ ์ทจํ–ฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

// Middleware
export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, types, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    const [REQUEST, SUCCESS, FAILURE] = types;
    next({ ...rest, type: REQUEST });
    return promise.then(
      (result) => next({ ...rest, result, type: SUCCESS }),
      (error) => next({ ...rest, error, type: FAILURE })
    );
  };
}

// Usage
function doSomethingAsync(userId) {
  return {
    types: [SOMETHING_REQUEST, SOMETHING_SUCCESS, SOMETHING_FAILURE],
    promise: requestSomething(userId),
    userId
  };
}

์˜ค, ๊ทธ ์†”๋ฃจ์…˜์ด ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. then() ๋ฐ dispatch() ๋Œ€ํ•œ ์ถ”๊ฐ€ ํ˜ธ์ถœ์„ ์ œ์•ˆํ•œ ์ฒซ ๋ฒˆ์งธ ์†”๋ฃจ์…˜๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ข‹์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด ๋งŒ์„ธ!

์–ด๋–ป๊ฒŒ(๊ทธ๋ฆฌ๊ณ  ;-) ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค!
์šฐ๋ฆฌ๋Š” ์ปค์Šคํ…€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋งŽ์ด ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

} (-1ํฌ์ธํŠธ ๐Ÿ˜€)๋ฅผ ๋นผ๋จน์—ˆ์ง€๋งŒ ๋งค๋ ฅ์ฒ˜๋Ÿผ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค! ์ฒ˜์Œ์œผ๋กœ.

:+1:

@erikras ์„œ๋ฒ„์—์„œ ์•ฝ์†์ด ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด์„œ ๊ตฌํ˜„ํ•œ ๋ฐฉ๋ฒ•์ด

์ด๊ฒƒ์€ ๋‹จ์ง€ ์˜์‚ฌ ์ฝ”๋“œ์ด๋ฏ€๋กœ ์•„๋ฌด๋ฐ๋‚˜ ๋ถ™์—ฌ๋„ฃ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด react-router(๋ˆ„์˜ API๊ฐ€ redux๋งŒํผ ๋น ๋ฅด๊ฒŒ ๋ณ€๊ฒฝ๋จ)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

app.get('/my-app', (req, res) => {
  Router.run(routes, req.path, (error, initialState) => {
    Promise.all(initialState.components
      .filter(component => component.fetchData) // only components with a static fetchData()
      .map(component => {
        // have each component dispatch load actions that return promises
        return component.fetchData(redux.dispatch);
      })) // Promise.all combines all the promises into one
      .then(() => {
        // now fetchData() has been run on every component in my route, and the
        // promises resolved, so we know the redux state is populated
        res.send(generatePage(redux));
      });
  });
});

๊ทธ๊ฒŒ ํ•ด๊ฒฐ์ด ๋˜๋‚˜์š”?

@ ๊ฐ€์žฅ

Slack์—์„œ ๋ฌธ์ œ๋ฅผ ์ธ์šฉ:

๋‚˜๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค.

 static async routerWillRun({dispatch}) {
   return await dispatch(UserActions.fooBar());
 }

์—ฌ๊ธฐ์„œ UserActions.fooBar() ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export function fooBar() {
 return dispatch => {
   doAsync().then(() => dispatch({type: FOO_BAR}));
 };
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์„œ๋ฒ„ ๋ Œ๋”๋ง์—์„œ ๋‹ค์Œ์„ ์‚ฐ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 yield myHandler.routerWillRun({dispatch: redux.dispatch});

ํ•˜์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” fooBar ์˜ ์ค‘์ฒฉ ๋ฉ”์„œ๋“œ์—์„œ ์‹ค์ œ๋กœ ์•„๋ฌด ๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ค‘๊ด„ํ˜ธ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜:

export function fooBar() {
  return dispatch =>
    doAsync().then(() => dispatch({type: FOO_BAR}));
}

๋˜๋Š” ๋ช…์‹œ์ ์ธ return ๋ฌธ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

export function fooBar() {
  return dispatch => {
    return doAsync().then(() => dispatch({type: FOO_BAR}));
  };
}

์–ด๋Š ์ชฝ์ด๋“  ์œ„์—์„œ ์ œ์•ˆํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž ์ง€์ • promise ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@erikras initialState.components (Router.run์˜ ์ฝœ๋ฐฑ์—์„œ)๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด fetchData ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋งˆ์ง€๋ง‰ ์˜๊ฒฌ๊ณผ ๊ด€๋ จํ•˜์—ฌ ๊ตฌ์„ฑ ์š”์†Œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฐœ์ฒด๋Š” ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ ํ•ธ๋“ค๋Ÿฌ๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์„ฑ ์š”์†Œ, ์ฆ‰ ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์— ๋„๋‹ฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์ƒ๊ฐ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์—ฌ๊ธฐ ๋‚ด๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์˜ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค

import React from 'react';
import Router from 'react-router';
import {Route, RouteHandler, DefaultRoute} from 'react-router';

//imagine Bar needs some data
const Bar = React.createClass({
  render(){
    return(
      <div>bar</div>);
  }
});

const Foo = React.createClass({
  render(){
    return (
      <div>
        foo
        <Bar/>
      </div>);
  }
});


const App = React.createClass({
  render(){
    return (
      <div>
        <RouteHandler />
      </div>
    );
  }
});

const routes = (
  <Route path="/" handler={App} name="App">
    <DefaultRoute handler={Foo} name="Foo"/>
  </Route>
);

Router.run(routes,'/',function(Root,state){
  console.log(state);
});

์‚ฐ์ถœ:

{ path: '/',
  action: null,
  pathname: '/',
  routes: 
   [ { name: 'App',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: false,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object],
       defaultRoute: [Object],
       childRoutes: [Object] },
     { name: 'Foo',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: true,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object] } ],
  params: {},
  query: {} }

๋ฃจํŠธ์˜ ๋ฐ”์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@erikras ํ™˜์ƒ์ ์ž…๋‹ˆ๋‹ค! ๋‚ด๊ฐ€ ๊ฐ€๊ณ  ์‹ถ์€ ๊ธธ์€ ๋ฐ”๋กœ ๊ทธ๋Ÿฐ ๊ธธ์ด๋‹ค. ๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@iest ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜๋ณตํ•˜์—ฌ ๋ง์žฅ๋‚œ์ด ์˜๋„์  ์ธ "๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์ด๋™"ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. :-)

@mattybow ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค. ๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฝ๋กœ์— ์—†๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ _์ •๋ง_ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ ์ผํ•œ ์˜ต์…˜์€ React.renderToString() ํ•œ ๋ฒˆ ์‹คํ–‰ํ•˜๊ณ (๊ฒฐ๊ณผ ๋ฌด์‹œ) componentWillMount() ์—์„œ ๋ชจ๋“  ๋กœ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ์–ด๋–ป๊ฒŒ๋“  ์•ฝ์†์„ ์ €์žฅํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ react-router ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์ง€์›ํ•˜๊ธฐ ์ „์— ์ž์ฒด ๊ฐœ๋ฐœํ•œ ๋ผ์šฐํŒ… ์†”๋ฃจ์…˜์œผ๋กœ ์ˆ˜ํ–‰ํ•œ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ๋กœ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋น„๊ฒฝ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์€ ์„ค๊ณ„ ๋ฌธ์ œ์˜ ์ฆ์ƒ์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๊ฒฝ๋กœ๋Š” ๊ตฌ์„ฑ ์š”์†Œ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@erikras
์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ์ „์ฒด ์˜ˆ์ œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐœ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@transedward ๊ทธ๋žฌ์œผ๋ฉด ์ข‹๊ฒ ์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋‚ด ๋ฌผ๊ฑด์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋งค์šฐ ๋ฏธ์ˆ™ํ•ฉ๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

๊ณ ๊ธ‰ ๋™ํ˜• ์˜ˆ์ œ์—์„œ +1
๋‚˜๋Š” ์ด๊ฒƒ์ด ์–ด๋””๋กœ ๊ฐ€๊ณ  ์žˆ๋Š”์ง€ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค!

@transedward ์—ฌ๊ธฐ์— ๋‚ด๊ฐ€ ํ•จ๊ป˜ ๋งŒ๋“  ๋ชจ๋“  ์ตœ์ฒจ๋‹จ ๊ธฐ์ˆ ์ด ํฌํ•จ๋œ ์ƒ˜ํ”Œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/erikras/react-redux-universal-hot-example/

@erikras ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค! ์ด README ๋ฐ React Hot Loader ๋ฌธ์„œ์˜ "์Šคํƒ€ํ„ฐ ํ‚คํŠธ" ์„น์…˜์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ฐ์‚ฌ ํ•ด์š”! PR์ด ์ œ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

@erikras ๊ทธ๋ ˆ์ดํŠธ - ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ด ๋Œ€ํ™”์˜ ์ผ๋ถ€ ์•„์ด๋””์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์•ฝ์†์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. https://github.com/pburtchaell/redux-promise-middleware.

@pburtchaell๋ฟ๋งŒ ์•„๋‹ˆ๋ผ @acdliteํ•˜์—ฌ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€์žˆ๋‹ค. https://github.com/acdlite/redux-promise

์ด์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ์ƒ๊ฐ:

  1. ์•ก์…˜์œผ๋กœ ๋ณ€ํ™˜๋˜๋Š” ํ”„๋ผ๋ฏธ์Šค๋Š” ์•ก์…˜๊ณผ ํ•จ๊ป˜ ์ „๋‹ฌ๋˜์–ด Redux Store์— ์ €์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋ชจ๋“  ์•ฝ์†์ด ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ „๋‹ฌ๋˜๋Š” ๋ชจ๋“  ์•ฝ์†์„ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•˜๊ณ  ๋ณด๋ฅ˜ ์ค‘์ธ ์•ฝ์†์ด ์—†์„ ๋•Œ๋ฅผ ์œ„ํ•œ ์•ฝ์†์„ ์ œ๊ณตํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์„ ํƒ์ž๊ฐ€ ๋ˆ„๋ฝ๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ž‘์—…์„ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

๋ฉ”์‹œ์ง€ 3์„ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ๋ฉ”์‹œ์ง€ ์ปจํ…Œ์ด๋„ˆ๋Š” <Message id={3}> ๋ Œ๋”๋งํ•˜๊ณ  ๋ฉ”์‹œ์ง€ ์„ ํƒ๊ธฐ๋Š” state.msgs[3] ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์—†์œผ๋ฉด ๋ฉ”์‹œ์ง€ ๋กœ๋”ฉ ์•ฝ์†์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‘ ๊ฐ€์ง€๋ฅผ ๊ฒฐํ•ฉํ•˜๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™ ์„ ํƒํ•˜๊ณ  ์™„๋ฃŒ ์‹œ์ ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋ชจ๋“  ์•ฝ์†์ด ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ „๋‹ฌ๋˜๋Š” ๋ชจ๋“  ์•ฝ์†์„ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•˜๊ณ  ๋ณด๋ฅ˜ ์ค‘์ธ ์•ฝ์†์ด ์—†์„ ๋•Œ๋ฅผ ์œ„ํ•œ ์•ฝ์†์„ ์ œ๊ณตํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

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

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

@wmertens ์˜ ๋งˆ์ง€๋ง‰ ์š”์ ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์ด ์ •๋ง ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋™์‹œ ํ˜ธ์ถœ์„ ํ”ผํ•˜๋Š” ๊ฒƒ(๋Œ€๊ธฐ ์ค‘์ธ ๊ฒฝ์šฐ ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ)์€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์ด๋ฉฐ ์ด์— ๋Œ€ํ•œ ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์ด ๋ฌด์—‡์ธ์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(actionCreator์—์„œ ์ €์žฅ์†Œ์˜ ์ƒํƒœ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—).

actionCreator ์‚ฌ์šฉ์ž(๊ตฌ์„ฑ ์š”์†Œ)๊ฐ€ ํ•ด๋‹น ์ž‘์—…์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ƒํƒœ์—์„œ ๋งค๋ฒˆ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋Ÿด ๋•Œ๋งˆ๋‹ค ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ๋ž˜ํ•‘ํ•˜๋Š” ๊ณ ์œ ํ•œ @connect ์ฃผ์„์„ ๋„์ž…ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

actionCreator์—์„œ ์Šคํ† ์–ด ์ƒํƒœ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—

์™œ์š”? ์ฝํฌ ๋ฏธ๋“ค์›จ์–ด ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function doSomething() {
  return { type: 'SOMETHING' };
}

function maybeDoSomething() {
  return function (dispatch, getState) {
    if (getState().isFetching) {
      return;
    }

    dispatch(doSomething());
  };
}

store.dispatch(maybeDoSomething());

๊ทธ๊ฒƒ์€ ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค!
๋‚˜๋Š” (์ด์œ  ์—†์ด) actionCreator์—์„œ ์ƒํƒœ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์œ ์Šต๊ด€์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค^^ ์•ก์…˜ ์ƒ์„ฑ์ž ํ˜ธ์ถœ์ž๊ฐ€ ์ƒํƒœ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— actionCreator๊ฐ€ ์ ‘๊ทผํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. :)

@gaearon ๊ฐ์‚ฌ

@gaearon ์€ http://gaearon.github.io/redux/docs/api/applyMiddleware.html ์œ„์˜ ๋‹ต๋ณ€๋ณด๋‹ค ์„ ํ˜ธ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ •์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

๊ธฐ๋ณธ๊ฐ’ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—… ์ƒ์„ฑ๊ธฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์ด

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }

๋˜ํ•œ,

๋‚˜๋Š” ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋‹ค์Œ์„ ์˜๋ฏธํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, result, readyState: 'success' }
{ type: SOMETHING, userId: 2, error, readyState: 'failure' }

์ž๋™ ์ƒ์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  success ๋˜๋Š” failure ์•ฝ์†์˜ ์ฝœ๋ฐฑ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์ž‘์—…์„ ์ƒ์„ฑํ•˜๋ ค๋Š”์ง€ ์—ฌ๋ถ€์— ๋‹ฌ๋ ค ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ท€ํ•˜์˜ ์ฝํฌ ์˜ˆ์—์„œ :

function makeASandwichWithSecretSauce(forPerson) {

  // Invert control!
  // Return a function that accepts `dispatch` so we can dispatch later.
  // Thunk middleware knows how to turn thunk async actions into actions.

  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ๋‹ค๋ฅธ ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋น„๋ฐ€ ์†Œ์Šค ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ์— ๋Œ€ํ•ด ์ผ๋ฐ˜ ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ˜๋“œ์‹œ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ฝํฌ ๋ชจ๋ธ์„ ์ข€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊น… ๋˜๋Š” "๋น„๋™๊ธฐ ์ง„ํ–‰ ์ค‘ ํ‘œ์‹œ๊ธฐ"์˜ ํ† ๊ธ€๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ๋ฏธ๋“ค์›จ์–ด์˜ ๋” ์ ์ ˆํ•œ ์˜ˆ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@justin808

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

ํŠธ๋ฆฌ๊ฑฐ๋œ ์ž‘์—…(๋กœ๋“œ, ์„ฑ๊ณต, ์‹คํŒจ)์˜ ์ƒํƒœ๋ฅผ ๋‹ค๋ฅธ ์ƒํƒœ์™€ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ActionStore๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด Redux/Flux์˜ ๊ธฐ๋ฐ˜์— ์œ„๋ฐฐ๋˜๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด stackoverflow ์— ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

@gabrielgiussi ๋‚ด ์ƒ๊ฐ์—๋Š” https://github.com/acdlite/redux-promise ๋˜ํ•œ ์ƒํƒœ์— ์•ฝ์†์„ ์ €์žฅํ•˜์ง€ ์•Š๊ณ ๋„ ์›ํ•˜๋Š” ๊ฒƒ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ๋Š” ํ•ญ์ƒ ์ง๋ ฌํ™” ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@wmertens ์กฐ์–ธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. repo๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์ง€๋งŒ ๋‚ด ์ƒํƒœ๊ฐ€ ์ง๋ ฌํ™”๋˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์ฐธ๊ณ ์šฉ์œผ๋กœ๋งŒ ๋ง์”€ํ•˜์‹œ๋Š”๊ฑด๊ฐ€์š”?

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

2015๋…„ 8์›” 10์ผ ์›”์š”์ผ 19์‹œ 15๋ถ„์— gabrielgiussi [email protected]์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

@wmertens https://github.com/wmertens ์กฐ์–ธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿด ๊ฒŒ์š”
repo๋ฅผ ์‚ดํŽด๋ณด์ง€๋งŒ ๋‚ด ์ƒํƒœ๊ฐ€ ์ง๋ ฌํ™”๋˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๋‹น์‹ 
์ฐธ๊ณ ๋งŒ ํ•˜๋ผ๊ณ ?

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

์›ŒํŠธ.
(๋ชจ๋ฐ”์ผ๋กœ ํƒ€์ดํ•‘, ๊ฐ„๊ฒฐํ•œ ๋ณ€๋ช…)

์‚ฌ์‹ค, ์Šคํ† ์–ด์—์„œ ์ปค์Šคํ…€ Action ๊ฐ์ฒด๋ฅผ ๋„ฃ์—ˆ๋Š”๋ฐ, ๊ทธ๊ฒƒ๋“ค์€ ๋‹จ์ง€ Immutable.Record์— ๋‹จ์ˆœํ•œ ์†์„ฑ(id, state, payload)๊ณผ Promise๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ์•ก์…˜ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์žˆ๋Š” ๋ ˆ์ฝ”๋“œ์ด๋ฏ€๋กœ ์Šคํ† ์–ด์— Promise๋ฅผ ๋‘์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„๋งˆ๋„ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๊นจ๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. @wmertens ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@gabrielgiussi

Promise๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ์•ก์…˜ ํŠธ๋ฆฌ๊ฑฐ

์ง๋ ฌํ™”ํ•  ์ˆ˜ ์—†๋Š” ํ•จ์ˆ˜๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ƒํƒœ์— ๋„ฃ์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋งํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ๋‹ค

Promise๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ํŠธ๋ฆฌ๊ฑฐ

๋‚ด๊ฐ€ ์‹ค์ œ๋กœ ์ƒ์ ์— ๋„ฃ๋Š” ๊ฒƒ์€ Action ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค(์ด๋ฆ„์ด ์ตœ๊ณ ๊ฐ€ ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค).

export default class Action extends Immutable.Record({state: 'idle', api: null, type: null, payload: null, id: null}){
load(){
  return this.set('state','loading');
}

succeed(){
  return this.set('state','succeeded');
}

fail(){
  return this.set('state','failed');
}

ended(){
  return this.get('state') != 'loading' && this.get('state') != 'idle';
}

endedWithSuccess(){
  return this.get('state') == 'succeeded';
}

endedWithFailure(){
  return this.get('state') == 'failed';
}

trigger() {
  return (dispatch) => {
    dispatch({type: this.get('type') + '_START', action: this});
    let payload = this.get('payload');
    this.get('api').call({dispatch,payload}).then((result) => {
      dispatch({type: this.get('type') + '_SUCCESS',id: this.get('id'), result: result.result});
    }).catch((result) => {
        dispatch({type: this.get('type') + '_FAIL',id: this.get('id'), result: result.result});
      });
  }
}
}

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค(#539 ์ฐธ์กฐ). ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋ณด๋ฅ˜ ์ค‘์ธ ์ž‘์—…์— ๋Œ€ํ•œ ์•ฝ์†์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ชจ๋“  ์•ฝ์†์ด ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@gaearon ๋‹น์‹ ์ด ์ž‘์„ฑํ•œ ์ด ์ฝ”๋“œ๋Š” https://github.com/rackt/redux/issues/99#issuecomment -112212639,

์ด๊ฒƒ์€ redux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ๊ฒƒ์ž…๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์ˆ˜๋™์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ์ด ์ƒˆ๋กœ์šด ์งˆ๋ฌธ์ด๋ผ๋ฉด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. React / Flux(Redux)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์‹ญ์‹œ์˜ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/happypoulp/redux-tutorial

@banderson5144

ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๋‹น์‹ ์ด ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋‹ค๋ฅด๊ฒŒ ํ•  ์ž์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
๋น„์Šทํ•œ ๊ฒƒ์ด https://github.com/pburtchaell/redux-promise-middleware ๋กœ ๊ฒŒ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

์ด ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ƒ์  ์žฌ์„ค์ •์— ๋Œ€ํ•œ ๋‹น์‹ ์˜ ๋‘๋‡Œ๋ฅผ ์„ ํƒํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค -

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

์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜์…จ๋‚˜์š”?/์–ด๋–ป๊ฒŒ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ์‹ ๊ฐ€์š”? ๊ฐ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด ์ƒ์ ์ด ๋Œ€์‹  ์ž‘๋™ํ• ๊นŒ์š”?

์„œ๋ฒ„ ๋ Œ๋”๋ง์„ ๋ง์”€ํ•˜์‹œ๋Š” ๊ฑด๊ฐ€์š”? ๋ชจ๋“  ์š”์ฒญ์— โ€‹โ€‹๋Œ€ํ•ด ์ƒˆ ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฌธ์„œ์— ์„œ๋ฒ„ ๋ Œ๋”๋ง์— ๋Œ€ํ•œ ๊ฐ€์ด๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•œ ํ›„ ...

๋„ˆ๋ฌด ์ˆœ์ง„ํ•œ๊ฐ€์š”? (์•„๋ฌด๋„ ์ด๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ œ ์ƒ๊ฐ์—๋Š”)

// server.js
app.use(function (req, res) {
    match({โ€ฆ}, function (error, redirectLocation, renderProps) {
        โ€ฆ

        if (renderProps) {
            const store = configureStore();

            const promises = renderProps.components.map(function (component, index) {
                if (typeof component.fetchData !== 'function') {
                    return false;
                }

                return component.fetchData(store.dispatch);
            });

            Promise.all(promises).then(function () {
                res.status(200).send(getMarkup(store, renderProps));
            });
        }
    })
});
// home.js
export class Home extends Component {
    static fetchData() {
        return Promise.all([
            dispatch(asyncAction);
        ]);
    },

    componentDidMount() {
        const { dispatch } = this.props;

        Home.fetchData(dispatch);
    }
}

export default connect()(Home);
// action.js
export function asyncAction() {
    return (dispatch, getState) => {
        dispatch(request);

        return fetch(โ€ฆ)
            .then(response => response.json())
            .then(data => dispatch(requestSuccess(data)))
        ;
    }
}

๋‚˜๋Š” ๋˜ํ•œ @mattybow ์˜ ์งˆ๋ฌธ https://github.com/rackt/redux/issues/99#issuecomment -112980776(๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ค‘์ฒฉ ๊ตฌ์„ฑ ์š”์†Œ)์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์„ ์ฐพ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์ง€๋งŒ ๊ทธ๋Ÿฌํ•œ ์„ฑ๊ณต์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋ ‡์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). componentWillMount ์—์„œ ์•ฝ์†์„ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

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

๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์€ ์ด๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ์— ์•„์ฃผ ์ข‹์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‹น์‹ ์„ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”

ํŽธ์ง‘: "componentDidMount"๊ฐ€ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋  ๋•Œ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ?

@ms88privat ์•„์ง ์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋งŽ์ด ๋ฐ›์ง€ ๋ชปํ–ˆ๊ณ  ํ•œ๊ณ„๋ฅผ ํ…Œ์ŠคํŠธํ•˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

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

๋‹น์‹ ์ด ๊ธฐ๋Œ€ํ•˜๋Š” ๋Œ€๋กœ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์œผ๋‹ˆ, ์ง€๊ธˆ์œผ๋กœ์„œ๋Š” ๊ทธ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.


componentDidMount ๊ฐ€ ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค(https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount ์ฐธ์กฐ). ์ด ๋ฐฉ๋ฒ• ๋˜๋Š” ํ•„์š”์— ๋งž๋Š” ๋‹ค๋ฅธ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์ ์ด ์ด๋ฏธ ๊ฐ€๋“ ์ฐฌ ๊ฒฝ์šฐ(๋˜๋Š” ์ ํ•ฉํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋ฌด์—‡์ด๋“ ) fetch ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ•˜๋Š” ๋‚ด์šฉ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๋Š” https://github.com/reactjs/redux/blob/master/examples/async/actions/index.js#L47 ์„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค.

@chemoish

์ƒ์ ์ด ์ด๋ฏธ ๊ฐ€๋“ ์ฐฌ ๊ฒฝ์šฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”.

๊ทธ๋Ÿฌ๋‚˜ ์œ„์— ์ œ์‹œ๋œ ์†”๋ฃจ์…˜์€ ๊ฐ ํŽ˜์ด์ง€๊ฐ€ ๋ชจ๋“  ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์–ด์ฉŒ๋ฉด ๋‚ด๊ฐ€ ๋‹น์‹ ์˜ ์†”๋ฃจ์…˜์„ ์ž˜๋ชป ์ฝ์—ˆ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์€ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์— ๊ด€๊ณ„์—†์ด ํ•„์š”ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์•„๋‹™๋‹ˆ๊นŒ? (์˜ˆ: SPA์ธ ๊ฒฝ์šฐ์—๋„ ํ˜„์žฌ ๊ฒฝ๋กœ์—์„œ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ๋™์ผํ•œ ์ƒํƒœ๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•จ)

๊ทธ๋Ÿด ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์–ด๋–ค ์ด์œ ๋กœ๋“  ์ค‘์ฒฉ๋œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ž์ฒด ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ๋ฐ˜๋ณต๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์ด์ง€๋งŒ ๊ฐ ํŽ˜์ด์ง€์—๋Š” ๋งŽ์€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@chemoish ๊ฐ™์€ ํŽ˜์ด์ง€์— ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ œ ๊ด€์ ์ด ๋ฌด์—‡์ธ์ง€ ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์„ธ ๊ฐœ์˜ ์ค‘์ฒฉ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • component1(์ •์  dataFetch1)

    • component2(์ •์  dataFetch2)

    • component3(์ •์  dataFetch3)

๊ทธ๋“ค ๊ฐ๊ฐ์€ ๊ณ ์œ ํ•œ dataFetching ์„ ์–ธ(์ •์  dataFetching ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•œ ๋””์ŠคํŒจ์นญ ์ž‘์—…)๊ณผ ํ•จ๊ป˜ ๊ณ ์œ ํ•œ "componentDidMount" ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

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

์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•˜๋ฉด match ํ•จ์ˆ˜์™€ renderProps ๊ฐ€ ์„ธ ๊ฐ€์ง€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ชจ๋‘ ์ถ”์ถœํ•˜๋ฏ€๋กœ ๋ชจ๋“  ์ •์  dataFetching ๋ฉ”์„œ๋“œ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง?

์ œ๊ณต๋œ ์˜ˆ์—์„œ match function ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ณ ๋งˆ์›Œ.

@ms88privat renderProps.components ๋Š” ๋ผ์šฐํ„ฐ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ฐฐ์—ด์ด๋ฉฐ, ๊ทธ ์ด์ƒ์€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @chemoish ๋Š” ๊ทธ์˜ ๊ตฌํ˜„์œผ๋กœ ๋” ๊นŠ์€ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์„ค๋ช…ํ•  ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๋‹ค.

@DominicTobias thx, ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋ชจ๋“  ์ค‘์ฒฉ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์•„๋งˆ๋„ ์ด๊ฒƒ์ด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? https://github.com/gaearon/react-side-effect
์ค‘์ฒฉ ์š”์†Œ์—์„œ ๋ชจ๋“  ๋ฉ”ํƒ€ ํƒœ๊ทธ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ: https://github.com/nfl/react-helmet

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

@erikras๊ฐ€ ์ƒ์šฉ๊ตฌ ํ”„๋กœ์ ํŠธ๋ฅผ redux-async-connect ๋กœ ์˜ฎ๊ฒผ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค . ๋ˆ„๊ตฐ๊ฐ€ ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

@vtambourine ์ €๋Š” https://github.com/markdalgleish/redial ์„ ๋ณด๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฝค ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ, ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ›„ํฌ ๊ฐ€์ ธ์˜ค๊ธฐ๋Š” ์ฝ”๋“œ๋ฅผ n์œผ๋กœ ์žฌ์ดˆ๊ธฐํ™”ํ•œ ํ›„ ๋‘ ๋ฒˆ์งธ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ณ ๊ฐ.
On ะŸั‚, 18 ะผะฐั€ั‚ะฐ 2016 ะณ. 22:54์—์„œ Sean Matheson [email protected]
์ผ๋‹ค:

@vtambourine https://github.com/vtambourine ๋‚ด๊ฐ€ ๋ณด๊ณ  ์žˆ๋˜
๊ฝค ๋„์›€์ด ๋˜๋Š” https://github.com/markdalgleish/redial

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/reactjs/redux/issues/99#issuecomment -198517067

๋˜ํ•œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์•ˆ์ •์ ์ธ ์†”๋ฃจ์…˜์„ ์ฐพ์•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. @erikras ์˜ ์ƒ์šฉ๊ตฌ๋ฅผ ์ข‹์•„ํ•˜์ง€๋งŒ @vtambourine์ด ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์•ˆ์ •์ ์ธ ์žฅ๊ธฐ ์†”๋ฃจ์…˜์ด ์•„๋‹Œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” redux-async-connect๋กœ ์ด๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. #81 redux-async-connect๊ฐ€ ์ฃฝ์—ˆ์Šต๋‹ˆ๊นŒ? .

@vtambourine https://github.com/makeomatic/redux-connect ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํฌํฌ๊ฐ€ ์žˆ์œผ๋ฉฐ ์ž˜ ๊ด€๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•ฝ๊ฐ„์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š” ์œ ์‚ฌํ•œ API๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€์‹ฌ ์žˆ๋Š” ๊ฒฝ์šฐ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

@gaearon์ด ์–ธ๊ธ‰ํ•œ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์žˆ๋Š” redux ์†”๋ฃจ์…˜์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์ด ๊ธฐ์ˆ ์„ ๊ตฌํ˜„ํ•˜๊ณ  ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด๊ฐ€ ์„œ๋ฒ„ ์ธก์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/peter-mouland/react-lego-2016#redux -with-promise-middleware

์ด ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ์ž‘์—… ์ƒ์„ฑ์ž๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

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