【问题标题】:When, why and how to use Action Creators in redux?何时、为什么以及如何在 redux 中使用 Action Creator?
【发布时间】:2017-05-07 12:33:18
【问题描述】:

我正在编写一个使用 Redux 的 ReSwift 实现的应用程序。我想知道,何时使用动作创建者,为什么?

阅读tutorial 后,我像创作者一样填写,只是在检查内部状态后才创建动作。例如,我有一个按钮,在用户按下它后,如果我处于状态 A,我想启动一些进程。所以,我必须编写一个动作创建器,它将检查当前状态,然后返回正确的动作,或者不动作一点也不。然后从同一个地方分派这个动作。

我说的对吗?我将非常感谢任何示例。

第二个问题 - 我必须在哪里实施它?

【问题讨论】:

    标签: ios swift redux


    【解决方案1】:

    我在我的博文Idiomatic Redux: Why Use Action Creators? 中介绍了这个主题。回顾重点:

    1. 基本抽象:与其在需要创建相同类型动作的每个组件中编写动作类型字符串,不如将创建该动作的逻辑放在一个地方。
    2. 文档:函数的参数可作为执行操作所需数据的指南。
    3. 简洁和干燥:在准备动作对象时可能会有一些更大的逻辑,而不是立即返回它。
    4. 封装和一致性:始终使用动作创建器意味着组件不必知道创建和调度动作的任何细节,无论是简单的“返回动作对象”函数还是具有大量异步调用的复杂 thunk 函数。它只是调用this.props.someBoundActionCreator(arg1, arg2),让动作创建者担心如何处理事情。
    5. 可测试性和灵活性:如果组件只调用作为 prop 传入的函数,而不是显式引用 dispatch,则可以轻松地为组件编写测试,改为传入函数的模拟版本。它还可以在其他情况下重用组件,甚至可以与 Redux 以外的其他东西一起使用。

    【讨论】:

    • 好的,我想我明白了。仍然-您能否回答这个问题:我有一个按钮,必须开始在某处发送信息的过程。但从逻辑上讲,只有当我的状态支持此发送时,它才必须发送它。否则,它必须向用户发送其他操作 - 消息,表明它尚未准备好。我必须把这种决定行动的逻辑放在哪里?
    • 这对于 thunk 函数来说是一个很好的用例。 Thunk 可以访问getState(),因此 thunk 可以检查 state 中的值并决定是否调度。根据我的评论,该组件只需调用this.props.someFunction(),无需进一步担心。我在gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857e 有一些常见的thunk 模式示例。
    【解决方案2】:

    Redux.js 和 ReSwift 的行为完全不同。

    在回答你的问题之前,让我先澄清一下。

    清理 Redux.js/ReSwift 的困惑

    ReSwift 中的动作创建者

    “Action creators”在 Redux.js 中是一个相当专业的术语,但从 v4 开始,ReSwift 中的类型是这样定义的:

    public typealias ActionCreator = (_ state: State, _ store: Store) -> Action?
    

    因此与一般建议相反,您确实可以在调度操作时访问状态。您不需要 Thunk 实现,尽管 Thunks 或 Epics 可以在更复杂的情况下提供帮助。

    “动作创建者帮助封装动作创建细节”

    那是相当拗口:)

    Redux.js 动作是对象字面量。如果你用 Swift 编写 Redux 操作,它们会更像 Dictionarys。这就是 Redux.js 中的 Action Creator 为工厂提供便利的方式(如“Factory”,Gang of Four 设计模式)。

    不过,ReSwift.Action 类型通常以自定义值类型 (structs) 实现。 ReSwift 不会遇到 Redux.js 操作的问题。这意味着通过在 ReSwift 中创建自定义动作 type,将动作创建集中在一个函数中的好处就消失了。你的类型的初始化器已经提供了这个。

    这描绘了一幅完全不同的画面。

    这可能就是ReSwift.Store.ActionCreator 进入该州的原因:提供任何好处。以与 Redux 不同的 API 为代价。

    适用于您的问题

    例如,我有一个按钮,当用户按下它后,如果我处于状态 A,我想启动一些进程。所以,我必须编写一个动作创建器,它将检查当前状态,然后返回正确的动作,或根本不采取行动。然后从同一个地方分派这个动作。

    有几种方法可以实现。

    如果您有权访问 store 变量以调用 dispatch,您也可以访问其当前的 state 属性。您可以向商店询问应用程序所处的状态并采取相应措施。通常,您会编写商店订阅者以获取有关商店更改的“推送通知”,但在这种情况下,您也可以询问商店。

    这意味着以下将是一个完全有效的实现:

    let currentState = store.state
    let action: Action = {
        if currentState.someSubstate == "A" {
            return ActionWhenInStateA()
        } else {
            return ActionWhenNotInStateA()
        }
    }
    store.dispatch(action)
    

    由于 ReSwift Stores 不应该接收来自不同线程的调度命令,因此您可以依赖第 1 行的状态与您调度的最后一行中的状态相同。

    TL;DR:您不需要ActionCreator 来实现这一点。但是,如果您喜欢编写“面向东方”的代码,则可以使用回调而不是属性查询:

    store.dispatch { state, _ in
        if state.someSubstate == "A" {
            return ActionWhenInStateA()
        } else {
            return ActionWhenNotInStateA()
        }
    }
    

    【讨论】:

      【解决方案3】:

      动作创建者只需创建要由您的商店分派以由您的 Reducer 处理的动作。

      为了方便起见,您应该使用 Action Creator 来防止每次需要调度操作时都声明对象。例如,想象下面的例子:

      <button onClick={() => { dispatch({ type: 'MY_ACTION'); }}>
      

      写起来更干净:

      <button onClick={() => { dispatch(myActionCreator()); }}
      

      而且它也更容易理解。

      它在组件内部很有用(例如 React),您可以在其中通过 props 注入它们并将它们作为普通函数调用(例如在按钮单击中)。

      有几种方法可以声明动作创建者。没有模式可以做到这一点。您可以创建一个名为 actions 的文件,将它们放在此文件中,您可以将它们与您的 reducer 一起编写。你决定。

      您可以查看documentation 来澄清您的想法。您还可以看到this 有趣的模式来声明您的动作创建者。

      希望对你有帮助。

      【讨论】:

      • 是的,它有帮助。您能否也告诉我,我应该在哪里声明选择动作的逻辑,具体取决于状态?例如,我想检查我是否在状态A,然后执行AAction,如果我在状态B - BAction。
      • 我明白了。您当前的状态与您的行为没有直接关系。您没有针对状态 A 的操作 A。您的操作会改变您的状态。您可以将任何内容传递给他们,并且他们需要具有标识操作的类型属性。例如,您可以在您的状态中将属性 isLoading 更改为 true 的操作。另一个将其改回假。您有两个更改同一属性的操作。您对动作 A 属于状态 A 没有任何限制。您只需调用它们并根据需要改变状态。
      • 我的意思是另一个问题:) 假设我有一个按钮,它必须开始在某处发送信息的过程。但从逻辑上讲,只有当我的状态支持此发送时,它才必须发送它。否则,它必须向用户发送其他操作 - 消息,表明它尚未准备好。我必须将这种确定行动的逻辑放在哪里?或者我只是发送一个动作'ButtonTapped'并在减速器中做其他事情?
      • 您可以根据您的实际状态树做出决定。例如,如果您已经从某个 API 获得了一些信息,那么您不需要再次执行 ajax 调用,对吗?你可以检查你的状态。将状态视为存储数据以供您在应用程序中使用和做出决策的数据库。关于逻辑,根据您的状态调用正确的操作取决于您。它可以从组件或异步操作中调用。取决于您的工作流程。如果你给我看一些代码,我可以更好地帮助你。
      猜你喜欢
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 2015-02-24
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      • 2018-03-05
      相关资源
      最近更新 更多