2015-11-06 4 views
1

Я думаю, через несколько сценариев, окружающих Redux, и я не смог найти чистое решение этого примера:Redux действия отправки в ответ на действия

Допустим, у вас есть компонент, который представляет собой список рецептов , Когда вы выберете рецепт из этого списка, вы получите dispatch(RECIPE_SELECTED). Этот асинхронный action-creator может делать дополнительные, связанные с рецептом - возможно, перейдите в async, чтобы получить ингредиенты для рецептов, сохраните выделение на сервере, что угодно.

В совершенно отдельном компоненте у вас есть список профессиональных поваров. Желаемое поведение заключается в том, что, когда пользователь выбирает рецепт, вы заполняете список профессиональных поваров любым шеф-поваром, у которого есть выбор выбранного рецепта.

Как вы слушаете RECIPE_SELECTED, а затем отправляете абсолютно несвязанное действие, имеющее зависимость от рецепта? Что-то вроде ...

when RECIPE_SELECTED:recipe 
    loadChefs(recipe).then(res => dispatch(CHEFS_LOADED, res.chefs)) 

Вы могли смешивать этот loadChefs/dispatch в остросюжетном создатель RECIPE_SELECTED, но это действительно полное смешение проблем и быстро плести запутанную паутину.

Вы также мог бы сделать некоторые очень важно (то есть против зерна для Redux) вещей, как так (с помощью React):

componentWillReceiveProps(nextProps) { 
    if (nextProps.recipe !== this.props.recipe) { 
    const { dispatch, recipe } = nextProps 
    dispatch(loadChefs(recipe)) 
    } 
} 

Я действительно не нравится ни один из этих решений. Мысли?

ответ

4

Вы знакомы с redux-thunk? https://github.com/gaearon/redux-thunk

С Redux-стуком применяется в качестве промежуточного слоя, вы можете сделать что-то вроде этого:

function selectRecipe(recipe) { 
    return function (dispatch) { 
     dispatch(setRecipe(recipe)); 
     return loadChefs(recipe).then((res) => 
      dispatch(setChefs(res.chefs)) 
     ); 
    }; 
} 

Где setRecipe и setChefs простые создатели действий. например

function setRecipe(recipe) { 
    return { 
     type: SET_RECIPE, 
     recipe 
    }; 
} 

function setChefs(chefs) { 
    return { 
     type: SET_CHEFS, 
     chefs 
    }; 
} 

Я рекомендую прочитать документы по действиям Async. http://rackt.org/redux/docs/advanced/AsyncActions.html

+0

Я думаю, что вы слишком быстро просмотрели мой вопрос: «Вы можете смешать эту загрузку/отправку в action-creator RECIPE_SELECTED, но это очень грубое смешивание проблем и быстрое переплетение запутанной сети». Одна из основных целей заключалась в том, чтобы избежать смешивания проблем между модулями. Почему создатель 'selectRecipe' должен знать, что он также должен делать' loadChefs'? Это не должно. Это смешивает полностью отдельные домены в один и тот же создатель действия ... что означает дальнейшее продвижение по пути, в котором у вас будет создатель действия в одном модуле, который содержит знания домена о десятках других модулей. – Clev3r

+0

Я не согласен. Если выбор нового рецепта приводит к загрузке в списке поваров, то они не являются отдельными проблемами. В редуксе нет такой вещи, как прослушиватель действий. Любая сложная логика (особенно async) принадлежит вашему создателю действия. Что вы можете сделать, так это разделить их на простых и сложных создателей действий, как показано выше. –

0

Другое решение заключается в использовании промежуточного программного обеспечения Redux-Saga. Это позволяет написать что-то вроде этого:

function* loadChefsSaga() { 
    # takeLatest sets up a system that spawns the inner generator every time 
    # an action matching the pattern is dispatched. If the inner generator 
    # is still running when additional actions are dispatched, it is cancelled, 
    # and a new one is spawned. 
    yield takeLatest('RECIPE_SELECTED', function* (recipe) { 
     # When a Promise is yielded, the generator is resumed when the Promise 
     # resolves. Alternatively, if it rejects, the rejected value is thrown 
     # into this generator. 
     const {chefs} = yield loadChefs(recipe) 

     # Assuming chefsLoaded is an action creator for CHEFS_LOADED 
     # `put` is redux-saga's equivelent of `dispatch`. We use it because 
     # the saga doesn't have direct access to the `dispatch` function. 
     yield put(chefsLoaded(chefs)) 
    }) 
} 

Я предполагаю, что у вас есть базовые знания с тем, как работает JavaScript генераторы. Если нет, то ищите их; они являются мощным образцом. В этом случае redux-saga использует их для построения функций, которые могут блокировать вещи. Каждый раз, когда что-то дается, редукс-сага рассматривает его как «Эффект», который он знает, как обрабатывать. Например, когда дается Promise, redux-saga устанавливает его так, что генератор возобновляется, когда Promise разрешает (или что-то бросается в генератор, если он отклоняет).

Смежные вопросы