【问题标题】:Why redux suggests to only connect to top level components?为什么 redux 建议只连接顶级组件?
【发布时间】:2015-12-11 00:22:15
【问题描述】:

我是 redux 和 react-redux 的新手,同时我正在尝试制作一个 redux 应用程序。

看不懂redux文档上的说法:

然后,我们使用 react-redux 中的 connect() 函数包装我们想要连接到 Redux 的组件。尝试仅对顶级组件或路由处理程序执行此操作。 虽然从技术上讲,您可以将应用中的任何组件连接()到 Redux 商店,但请避免这样做太深,因为这会使数据流更难追踪。

连接所有组件不是更容易,当状态更新时,每个组件都可以得到新的状态树?

为什么是哑组件和高级容器?

谢谢。

【问题讨论】:

标签: reactjs redux


【解决方案1】:

如前所述,Abramov(Redux 作者)已经撤回了他的建议:connect()ed 组件。他在this Reddit post on the topic 中阐述了一个很好的经验法则:

我是这样做的:

  1. 从使用一个容器和几个展示组件开始

  2. 随着展示组件树的增长,“中间”组件开始向下传递太多道具

  3. 此时,我将一些叶子组件包装到容器中,这样“中间”组件就不需要接受和传递与它们完全无关的道具

  4. 重复

如果您观看我在 Egghead 课程中的最后十个视频,这正是我展示的方法:https://egghead.io/series/getting-started-with-redux

根据我的阅读,connect() 的初步建议与性能无关,而是与模块化组件和大型应用程序中数据流的易于推理有关。

事实上,与 1-container-to-rule-them-all-top-heavy 模式相比,更多 connect()ed 组件可能具有性能优势。 Abramov once more:

这两种方法都很好,嵌套的 connect() 组件实际上会给你更多的性能。缺点是它们与应用程序的耦合度稍高一些,测试起来也稍微困难一些,但这可能不是大问题。

【讨论】:

    【解决方案2】:

    当我在顶部有一个容器时,我遇到了效率问题,因为 React 在树中某处的最轻微更新期间重新渲染了我的所有组件。所以我放弃了这种方法,并针对文档制作了我的应用程序,结果证明速度更快。

    但后来我看到连 Redux 的作者都在他的 Twitter 上写道:

    在 Redux 示例中强调“顶部有一个容器组件”是错误的。不要把这当作格言。

    https://twitter.com/dan_abramov/status/668585589609005056

    尝试将您的演示文稿组件分开。在方便时通过连接它们来创建容器组件。 https://twitter.com/dan_abramov/status/668586001175048192

    【讨论】:

      【解决方案3】:

      答案在您摘录的文档的本节中:

      虽然从技术上讲,您可以将应用中的任何组件连接()到 Redux 存储,避免这样做太深,因为它会使数据流动 更难追踪。

      Redux 的核心原则之一是数据通常应该自上而下流动,即它应该是单向的。如果您connect 太多较低级别的组件,则您的数据流不再是单向的。 这样做的主要后果是组件之间更容易出现不一致的状态。

      当采用自上而下时,当您只连接有限数量的高级组件时自然会发生这种情况,创建状态不一致的情况要困难得多,因此文档中的建议。

      【讨论】:

      • 正如其他人在他们的回答中指出的那样,这现在被认为是 Redux 的创建者早期的错误方向。
      【解决方案4】:

      阅读我在此处发布答案时的最新答案,我想进一步增加使用官方Redux style guide 连接每个组件的共识:

      希望有更多 UI 组件订阅 Redux 存储并以更精细的级别读取数据。这通常会带来更好的 UI 性能,因为当给定状态发生变化时需要渲染的组件更少。

      例如,不仅连接<UserList> 组件并读取整个用户数组,还让<UserList> 检索所有用户ID 的列表,将列表项呈现为<UserListItem userId={userId}>,并连接<UserListItem>并从商店中提取自己的用户条目。

      这适用于 React-Redux connect() API 和 useSelector() 钩子。

      【讨论】:

        【解决方案5】:

        在某些情况下,您可以更深入地使用connect()ed 组件。我不会如此严格地解释文档。

        一般来说,如果您发现自己从组件中传递了太多道具并且进行传递的组件没有使用这些道具,那么可以将它们移动到单独的容器组件中。

        如果你发现自己不断地在组件链中编写 props,那么可能是时候添加一个容器了:

        // A blog post view component
        render () {
          const {post} = this.props;
        
          return (
            <div>
              <h1>{post.title}</h1>
        
              <Author author={this.props.author}
                onClick={this.props.favAuthor}
                onHover={this.props.authorDetails}
                isAuthorFaved={this.props.isAuthorFaved}
                isAuthorFollowed={this.props.isAuthorFollowed}/>
            </div>
          )
        }
        

        在这种情况下,post 组件没有任何用途或需要用于&lt;Author/&gt; 的任何道具。您可能要考虑改为使用&lt;AuthorContainer author={this.props.author}/&gt;。作者属于该帖子,因此您将需要该信息。其余的可以使用容器的mapStateToProps(state, ownProps) 函数中的状态计算,其中ownProps.author 是作者对象。

        同样,这是一个人为的例子,但最终的逻辑属于你自己。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-02
          • 2020-11-01
          • 1970-01-01
          • 2018-10-26
          • 2014-12-03
          • 2017-09-07
          相关资源
          最近更新 更多