Redux调度操作以响应操作

时间:2015-11-06 22:19:11

标签: reactjs reactive-programming redux

我正在考虑围绕redux的一些场景,我无法找到这个例子的干净解决方案:

假设您有一个组件列表。当您从该列表中选择食谱时,您dispatch(RECIPE_SELECTED)。那个异步动作创建者可以做一些与配方有关的附加内容 - 也许是异步获取配方的成分,将选择保存到服务器,无论如何。

在一个完全独立的组件中,您有一份专业厨师名单。期望的行为是,当用户选择食谱时,您可以使用任何具有所选食谱变体的厨师填充专业厨师列表。

你如何监听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))
  }
}

我真的不喜欢这两种解决方案。想法?

2 个答案:

答案 0 :(得分:4)

你熟悉redux-thunk吗? https://github.com/gaearon/redux-thunk

将redux-thunk应用为中间件,你可以这样做:

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

setRecipesetChefs是简单的动作创作者。 e.g。

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

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

我建议您阅读有关Async Actions的文档。 https://redux.js.org/advanced/async-actions

答案 1 :(得分: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使用它们来构造可以阻止事物的函数。每次产生某些东西,redux-saga都会将其视为一种效果"它知道如何处理。例如,当产生Promise时,redux-saga将其设置为当Promise解析时生成器恢复(或者如果它拒绝则抛出某些东西)。