何处在Redux

时间:2017-06-01 10:05:48

标签: javascript reactjs redux redux-thunk

tl; dr我想知道在redux架构中将上下文特定的多步异步回调逻辑放在哪里,如果我在下面提供的示例代码的正确轨道上。通过“多步”和“特定于上下文”,我通常表示由某些用户操作(onClicks等)启动的服务器调用,其中逻辑可能仅与给定组件相关(例如在成功时重定向到给定路由)。

有关副作用的代码的redux docs has this to say

  

通常,Redux建议具有副作用的代码应该是动作创建过程的一部分。虽然该逻辑可以在UI组件内部执行,但通常将该逻辑提取到可重用的函数中是有意义的,这样可以从多个位置调用相同的逻辑 - 换句话说,就是一个动作创建器函数。

虽然这看起来不错,但我并不完全确定将调用放到我的路由组件是否“正确”,因为这些动作创建者通常看起来非常通用,并且触发路由到应用程序中的其他资源通常非常依赖上下文。

我还发现,放置这些完全不同的动物,以异步方式触发动作创建者,并在与“干净”同步动作创建者相同的文件(foo-model/actions.js)中调度生成的动作,这有点奇怪。这是对的地方吗?在阅读Redux上的教程时,它们似乎并存。

示例代码非常简单,基本上描述了这些步骤:

  1. 在用户点击时,使用某个参数调用函数
  2. 此函数调用另一个异步功能(例如网络呼叫)
  3. 当异步调用完成时,触发对另一页的路由操作
  4. 背景:我希望通过将所有Meteor特定位从React组件中移出来逐步重构Meteor项目,最终将Meteor替换为正面和背面的其他内容。由于大约有50KLOC,我不能一次性完成这项工作,所以我逐步通过一条路径,希望最终得到一个标准的React + Redux + ReduxRouter包。在当前的代码路由中,数据获取和呈现在每个组件中都有些交织在一起,我在查找多步异步逻辑的位置时遇到了一些麻烦,例如下面的例子。

    关于筹码的详细信息我试图解决这个问题:

    • 用于路由的FlowRouter
    • 用于数据变异和检索的Meteor / MiniMongo
    • React Komposer更高阶组件

    MyContainerComponent中的旧Meteor代码

    // triggered as onClick={(e) => this.saveEncounter(e.target.value)}
    // in render()
    const saveEncounter = (encounter) => {
        Meteor.call('createEncounter', encounter, handleSaveResult);
      }
    };
    
    const handleSaveResult = (err, encounterId) => {
      if (err) {
        this.setState({errorMessages: err});
      } else {
        // route to another page
        NavigationActions.goTo('encounter', {encounterId: this.props.encounter._id || encounterId});
      }
    }
    

    新的redux代码 - 移入actions.js

    我正在努力保持实施直接(没有额外的deps)此时理解基础。使用redux-thunkredux-actionsredux-saga的“简化”需要稍后进行。以example code in the Redux tutorial for Async Actions

    为模型
    export const saveEncounter = (encounter) => {
    
        function handleSave(err, encounterId) {
            if (err) {
                dispatch(createEncounterFailure(err), encounter);
            } else {
                dispatch(createEncounterSuccess(encounterId));
            }
        }
    
        dispatch(createEncounterRequest(encounter));
        Meteor.call('createEncounter', encounter, handleSave);
    }
    
    
    // simple sync actions creators
    export const CREATE_ENCOUNTER_REQUEST = 'CREATE_ENCOUNTER_REQUEST';
    function createEncounterRequest(encounter) {
        return {
            type: CREATE_ENCOUNTER_REQUEST,
            encounter
        };
    }
    export const CREATE_ENCOUNTER_FAILURE = 'CREATE_ENCOUNTER_FAILURE';
    function createEncounterFailure(error, encounter) {
        return {
            type: CREATE_ENCOUNTER_FAILURE,
            error,
            encounter
        };
    }
    export const CREATE_ENCOUNTER_SUCCESS = 'CREATE_ENCOUNTER_SUCCESS';
    function createEncounterSuccess(encounterId) {
        return {
            type: CREATE_ENCOUNTER_SUCCESS,
            encounterId
        };
    } 
    

3 个答案:

答案 0 :(得分:1)

我明白你的意思,你想有办法划分和分类你的行为,是吗?将执行同步代码,异步代码,记录器等的操作

就个人而言,我使用了一些命名约定。如果我必须发送一个必须获取某些数据的操作,我称之为REQUEST_DATA。如果必须将从服务器到达的一些数据存储到ReduxStore,我称之为STORE_DATA

我没有特定的模式。我还必须指出我根据功能划分我的代码库,所以我定义我的动作的模块非常小而且整洁

答案 1 :(得分:1)

正如您在评论中指出的那样,Dan Abramov在他对how to dispatch an action with a timeout的回答中讨论了处理Redux异步工作的许多想法。他还在why do we need middleware for async flow in Redux?中写了另一个很好的答案。

您可能需要阅读我Redux Side EffectsReact/Redux links list类别中的其他一些文章,以便更好地了解在Redux中处理异步逻辑的方法。

一般来说,听起来你可能想要使用" sagas"或"可观察者"用于管理您的某些异步逻辑和工作流程。有异形行为的Redux中间件种类繁多 - 我在博文The Tao of Redux, Part 2 - Practice and Philosophy中总结了主要类别和最受欢迎的库。在一个名为Redux Saga in Action的帖子中,对于一个非常分离的基于传奇的Redux架构也有一些有趣的想法。

答案 2 :(得分:0)

根据我使用Redux的经验,我没有发现将异步调用放入动作创建者中的任何问题。我认为redux-thunk或其他一些中间件非常有用,即使是简单的设置。

我唯一要补充的是,我发现你的示例代码不太可读。

就我个人而言,我喜欢the ducks pattern,但只是将动作类型,动作创建者和缩减器保存在单独的文件中可以提高清晰度。

希望这有帮助。