【问题标题】:React, Flux, State and Stores反应、通量、状态和存储
【发布时间】:2014-07-18 20:17:09
【问题描述】:

我发现示例 todo Flux 应用程序有点欠缺,所以我试图通过开发一个应用程序来学习和实验来了解情况。

该应用程序是一个拖放式水果篮组织器。我有几个篮子,可以在它们之间拖着各种水果。您可以通过单击突出显示一个水果,最后拖动的项目将保持突出显示。

基于此,我有 3 家商店:

  • 水果店
  • BasketStore
  • AppStateStore - 跟踪最后点击和最后拖动的水果

当用户操作发生时,如果水果被点击,则由 AppStateStore 调度和处理 FruitAction,如果水果被移动到另一个篮子,则由所有商店处理。

主 AppView 组件监听来自 FruitStore 和 AppStateStore 的更改事件并重新渲染。

我的问题是:

  • 对于这种情况,这是一个好方法吗?
  • AppView 是否应该监听多个商店?我应该如何防止 AppView 连续渲染多次?现在,当水果被移动时,FruitStore 和 AppStateStore 都会触发更改事件,导致连续两次渲染。
  • React 网站上的 Flux 文章显示了分派操作对象的视图(例如 AppDispatcher.dispatch(TodoActions.updateText()) ),但如果操作自己分派(例如仅 FruitActions.moveBasket() )和AppView 不知道 AppDispatcher?
  • 目前只有 AppView 监听商店,但如果要突出显示,单个 Fruit 组件是否应该监听 AppStateStore 以仅重新渲染它们自己?
  • 是否有更完整的 Flux 架构或类似架构示例?

【问题讨论】:

  • 您是否在任何地方发布了示例代码?
  • 我投票的范围太广了,因为对于一个问题来说,这个问题实在是太多了。我认为它需要更加专注。
  • @demongolem:感谢您的提示。以后我会牢记这一点。
  • @Lucas:暂时没有
  • 你的标题中漏掉了一个词——Redux,它是 React 最著名的通量实现。

标签: reactjs reactjs-flux


【解决方案1】:
  • 这种方法听起来很可靠。我会为每次交互创建完全不同的动作,例如FruitClickedFruitDragged 都可以是行动,商店会关注他们关心的人。
  • AppView 应该监听它获取数据的所有商店。如果您在同一滴答声中多次调用 setState,React 将智能地合并它们,因此您实际上不会多次渲染。
  • React 网站上的文章确实谈到了在 Creating Semantic Actions 下调度自己的操作。在代码块中向上滚动几页,您可以看到代码:

    _onDestroyClick: function() { 
      TodoActions.destroy(this.props.todo.id); 
    } 
    
  • 文章还谈到了哪些组件应该监听Listening to Changes with a Controller-View中的store:

    我们需要一个靠近组件层次结构顶部的 React 组件来监听 store 中的变化。在一个更大的应用程序中,我们会有更多这样的监听组件,也许页面的每个部分都有一个。在 Facebook 的广告创建工具中,我们有许多类似控制器的视图,每个视图都管理 UI 的特定部分。在 Lookback Video Editor 中,我们只有两个:一个用于动画预览,一个用于图像选择界面。

    有时我们可能需要在层次结构的更深处添加额外的控制器视图以保持组件简单。这可能有助于我们更好地封装与特定数据域相关的层次结构部分。但是请注意,层次结构中更深的控制器视图可能会通过为数据流引入一个新的、潜在冲突的入口点来违反单一的数据流。在决定是否添加深度控制器视图时,平衡简单组件的增益与在不同点流入层次结构的多个数据更新的复杂性。这些多次数据更新可能会导致奇怪的效果,React 的渲染方法会被来自不同控制器视图的更新重复调用,这可能会增加调试的难度。

  • 如果您对通量架构感兴趣,您可能对Fluxxor 感兴趣(免责声明:我写的),它(希望)有助于构建基于通量的应用程序。它有一个更强大的调度程序和一些其他更改(例如非全局存储/操作、React 混合),在许多情况下使事情变得更容易。

【讨论】:

  • 感谢您的澄清。我在开始之前查看了 Fluxxor,它看起来很棒,但我想在将它留给图书馆之前了解其中的本质。也感谢您纠正我的“语义动作”。我显然误读了。你谈到 React 将动作合并到一个刻度中;这是否意味着 React 在发生变化时使用 rAF 或类似的东西?
  • @user3687035 我对此不是 100% 确定的,但我认为 React 默认只在下一个刻度上呈现(例如通过 setTimeout);有一个 RAF 策略 in the React repo/codebase,但我认为目前没有使用。
  • 更新:React 在合成事件(例如onClick)被处理后自动合并渲染;如果您异步更改状态,例如在 setTimeout 或 Ajax 处理程序中,如果您将状态更改包装在 React.addons.batchedUpdates(在 v0.12.0 中添加),它只会批量更新。
  • 那个多重渲染问题呢?这是一个问题吗?我的理解是,由于 DOM 差异,如果 React 组件发生实际变化,则 DOM 组件将呈现。因此,发出更改不会自动重新渲染任何内容。
【解决方案2】:

如果不进一步了解应用程序,很难说这种方法是否好。

但是,在我看来,点击水果应该由 FruitStore 处理。也就是说,一个水果已经获得了活跃状态,变成了可拖动的。如果这会以某种方式影响整个应用程序,那么也许这也会导致 AppStateStore 发生变化。同样,将水果从一个篮子转移到另一个篮子似乎是 BasketStore 的领域。

我想象 FruitStore 包含这样的私有数据结构:

var _fruit = {
  1234: {
    id: '1234',
    type: 'apple',
    active: false
  },
  2345: {
    id: '2345',
    type: 'orange',
    active: false
  },
  3456: {
    id: '3456',
    type: 'apple',
    active: false
  }
};

我想象 BasketStore 有一个如下所示的私有数据结构:

var _baskets = {
  4321: {
    id: '4321',
    name: 'Josephine\'s Basket',
    fruitIDs: [
      1234,
      2345
    ]
  },
  5432: {
    id: '5432',
    name: 'Harold\'s Basket',
    fruitIDs: [
      3456
    ]
  }
};

因此,水果“活动”状态由 FruitStore 管理,篮子中的内容由 BasketStore 管理。

因此,如果这对您的应用程序有效,那么 AppView 可以监听这两个商店。如上所述,重复调用 render() 方法的成本非常低。这不会在每次调用时都触及 DOM——这是 React 的最大优势之一。 React 将智能地对调用进行批处理,并且只更新 DOM 的“脏”部分(如果有的话)。

但也许您可能希望将篮子变成控制器视图。如果您确实选择让您的水果成为控制器视图,请务必在 componentWillUnmount() 中清理侦听器,因为水果从篮子到篮子的移动可能需要销毁并重新创建它们。我认为在篮子级别聆听更有意义,但我还是不太了解您的应用。

回答你的最后一个问题:

是否有更完整的 Flux 架构或类似架构示例?

Facebook 的工程师现在正在研究一个更复杂的应用程序示例,该示例将展示 waitFor() 和服务器端持久存储的使用。我们希望尽快发布。

【讨论】:

    猜你喜欢
    • 2017-06-20
    • 2023-02-23
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 2021-02-22
    • 2015-08-15
    相关资源
    最近更新 更多