【问题标题】:Race Condition in Store between `render` and `componentDidMount``render` 和 `componentDidMount` 之间 Store 中的竞争条件
【发布时间】:2015-12-04 20:53:38
【问题描述】:

componentDidMount 中设置 Store 侦听器,同时不调用 setStateforceUpdate(从而触发立即重新渲染)是否安全?

在 React 中常见的例子似乎是在监听之前同步 getInitialState 中的 Store 状态或拉取存储数据在 render 中,然后在 componentDidMount 中开始监听。在componentDidMount 中渲染和设置侦听器之间的时间间隔内,是什么防止了 Store 更改丢失?

如果子组件在其componentDidMount 中采取同步操作来更改存储,父组件会不会错过此更改?

如果子组件在componentDidMount 中发出异步操作,是否有可能以父组件忽略的方式更改 Store?

React 组件生命周期中是否存在异步事件可以进入的空白?

来自抢占式异步编程背景,javascript 中缺乏显式同步保护,而在协作异步编程中通常是不必要的,这真的让我感到不安。

【问题讨论】:

    标签: javascript reactjs reactjs-flux


    【解决方案1】:

    经过一些测试和挖掘源代码后,我得出的结论是,在初始组件生命周期的任何地方都无法触发异步事件(getInitialState -> componentWillMount -> render -> Children -> componentDidMount)。

    从可以更改 Store 的子组件调用的同步事件肯定会在父组件调用 componentDidMount 之前解决,并导致视图和数据不同步。

    我得出的结论是,不在componentWillMount 中注册 Store 侦听器的唯一原因是它们不应该在同构应用程序的服务器上运行。在我看来,这不是充分的理由,因为它注册了不按文档顺序的侦听器(这可能会影响性能),并且有可能在初始渲染期间丢失对 Store 的同步更改。从概念上讲,这也是错误的地方。

    我打算在 componentWillMount 中注册我的听众,并附上浏览器测试:

    componentWillMount: function () {
      if (typeof window !== "undefined") {
        // register listener in browser only
      }
    }
    

    【讨论】:

    • 或在每个组件上设置一个静态方法,该方法从您的 url 获取 store 和 params,然后收集 stores 方法(这将返回 Promise)。
    • @limelights 我不完全理解您的评论,但我认为您可能在谈论 AJAX 商店,而我在谈论 Flux 商店。
    • 通量存储的常见做法是在从您的侦听器调用的函数中使用 'getStateFromStores()` 或类似函数 - 从存储中获取 state。这样,如果您错过了商店中的 x 个更新周期,您的获取将从商店获取最新状态,这意味着所有更改都已处理,然后重新呈现最新状态。
    • @wintvelt 这就是疯狂所在。您假设更新会在您错过的更新之后及时更新。
    • 问题的根本原因可能在其他地方:让子组件在子组件的初始渲染周期中某处触发存储更改。恕我直言,这可以而且应该避免。让组件 + 所有子组件的渲染周期完成,然后让任何组件执行某些操作来触发存储更新。可以让有状态的孩子从商店阅读。有状态的孩子不能改变商店。在组件树中向上移动这些调用并将结果作为道具传递给子级。
    猜你喜欢
    • 2016-02-02
    • 2013-11-14
    • 2016-11-16
    • 1970-01-01
    • 2012-06-24
    • 2016-01-06
    • 1970-01-01
    • 2021-11-02
    • 2015-01-16
    相关资源
    最近更新 更多