2015-11-06 38 views
1

我想通过周围Redux的一些场景,我没能找到一个干净的解决方案,以这个例子:Redux的派遣行动

比方说,你有一个组件,它是食谱的列表。当您从该列表中选择一个配方时,您需要dispatch(RECIPE_SELECTED)。异步动作创建者可能会做与配方有关的其他附加信息 - 可能是异步获取配方的配料,将选择保存到服务器,无论如何。

在一个完全独立的组件中,你有一个专业厨师名单。理想的行为是,当用户选择食谱时,与任何具有所选食谱变体的厨师一起填写专业厨师名单。

你怎么听RECIPE_SELECTED,然后调度一个完全不相关的行为,依赖于配方?喜欢的东西...

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

可以混合此loadChefs/dispatchRECIPE_SELECTED行动创造者,但是这是一个关注十分难看的混合和将迅速编织错综复杂的。

你也可以做一些非常必要的(即对粮食的终极版)的东西,像这样(使用反应):

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

我真的不喜欢这两种解决方案。思考?

回答

4

您是否熟悉redux-thunk? https://github.com/gaearon/redux-thunk

随着应用中间件终极版,形实转换,你可以做这样的事情:

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

setRecipesetChefs是简单的动作创造者。例如

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

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

我建议阅读有关异步操作的文档。 http://rackt.org/redux/docs/advanced/AsyncActions.html

+0

我认为你太快剔除了我的问题:“你可以将这个loadChefs/dispatch混合到RECIPE_SELECTED的动作创建者中,但是这实际上是一个严重混淆的问题,并且会很快编织一个纠结的网络。其中一个主要目标是避免模块之间的混合问题。为什么'selectRecipe'创建者必须知道它也应该执行'loadChefs'?它不应该。这是将完全独立的域混合到同一个动作创建者中......这意味着更远的路上你将有一个动作创建者在一个模块中,该模块持有关于数十个其他模块的领域知识。 – Clev3r

+0

我不同意。如果选择一个新配方导致加载厨师名单,那么他们不是单独的关注。在redux中没有这样的动作监听器。任何复杂的逻辑(特别是异步的东西)都属于您的行为创建者。你可以做的是将他们分成简单和复杂的动作创作者,如上所示。 –

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解析时(或者如果它拒绝时将其放入生成器)恢复生成器。