javascript - 将商店状态作为 Prop 传递,还是每个组件访问全局商店?

标签 javascript reactjs flux

我对以下语句感到有些困惑:“呈现整个应用程序”和“将状态传递给子组件”。

示例 1:

我有一个带有 AppComponent 的待办事项应用程序和 TodosListComponent . AppComponent从商店中获取待办事项数组并将其作为属性传递给 TodosListComponent .

示例 2:

我有一个巨大的应用程序,有很多状态。我有 50 个组件构建我的应用程序。我想从 AppComponent 传递商店的所有状态吗?遍历所有 50 个组件?

所以我想知道,约定是什么?让各个组件直接监听他们关心的 store 对我来说更有意义。优点是只有个别组件重新渲染,但为什么会有“整个应用程序在状态改变时重新渲染”的概念呢?

各自的优缺点是什么?什么是共同约定?

最佳答案

有几种方法可以处理这个问题。我认为它们都是有效的,并且有自己的权衡。

获取所有状态并将它的一部分传递给 child

这是您专门询问的技术。使用此方法,您将拥有一些可用于顶级组件的函数或方法,这些函数或方法将存储中的所有数据转换为“状态大包”,然后您将有选择地将这些数据的片段传递给子组件。如果这些组件有自己的 child ,他们会根据需要传递它。

这种方法的好处是它使事情通常易于调试。如果你必须改变从 store 中检索状态的方式,你只需要在顶级组件中改变它——只要它以相同的名称传递下去,其他组件就会“正常工作。 ”如果某些数据是错误的,您只需查看一个地方即可找出原因。

这种技术的缺点我称之为“ Prop 爆炸”——你最终可能会传递很多属性。我在一个中等规模的flux应用中使用了这个方法,顶层应用组件的一个片段看起来是这样的:

<section id="col-left">
  <Filters loading={this.state.loading}
            events={this.state.events}
            playbackRate={this.state.videoPlayback.playbackRate}
            autoPlayAudio={this.state.audioPlayback.autoPlay}
            role={this.state.role} />
</section>

<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
  <SessionVideo videoUuid={this.state.session.recording_uuid}
                lowQualityVideo={this.state.session.low_quality_video_exists}
                playbackRate={this.state.videoPlayback.playbackRate} />
  <section id="transcript">
    <Transcript loading={this.state.loading}
                events={this.state.events}
                currentEvents={this.state.currentEvents}
                selection={this.state.selection}
                users={this.state.session.enrolled_users}
                confirmedHcs={this.state.ui.confirmedHcs}

                currentTime={this.state.videoPlayback.position}
                playing={this.state.videoPlayback.playing} />
  </section>
</section>

特别是,在顶级组件和某些最终子组件之间可能有很多组件,除了传递数据外,对数据不做任何事情,将这些组件更紧密地耦合到它们在层次结构中的位置。

总的来说,我喜欢这种技术提供的可调试性,尽管随着应用程序变得越来越大和越来越复杂,我发现只用一个顶级组件来做到这一点是不明智的。

获取所有状态并将其作为一个对象传递

Facebook 的一位开发人员提到了这种技术。在这里,您将获得一大袋状态,就像上面一样,但是您将传递整个事物(或它的整个子部分)而不是单个属性。通过使用 React.PropTypes.shape在子组件中,您可以确保传递正确的属性。

好处是你传递的属性(property)更少;上面的例子可能看起来更像这样:

<section id="col-left">
  <Filters state={this.state} />
</section>

<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
  <SessionVideo session={this.state.session}
                playback={this.state.videoPlayback} />
  <section id="transcript">
    <Transcript state={this.state} />
  </section>
</section>

缺点是处理状态形状的变化变得有点困难;而不是仅仅更改顶级组件,您必须跟踪使用该数据的所有地方并更改组件访问属性的方式。另外,shouldComponentUpdate实现起来可能会变得有点棘手。

允许组件获得自己的状态

另一方面,您可以授予特定于应用程序(即不可重用)的子组件访问存储并根据存储更改事件建立自己的状态。像这样构建自己状态的组件有时被称为“ Controller View ”,或者现在更常见的是“容器组件”。

当然,好处是您根本不必处理传递属性(除了更改处理程序和更多可重用组件的属性)。

但是,缺点是您的组件与存储的耦合度更高——更改存储或它们提供的数据(或它们提供数据的接口(interface))可能会迫使您重新访问大量组件的代码。

此外,正如评论中提到的,这可能会使服务器渲染更加困难。如果您只使用属性(尤其是仅在顶层),您可以更轻松地将它们传输到客户端并使用相同的属性重新初始化 React。通过允许存储确定它们自己的数据,您需要以某种方式将该数据注入(inject)存储中,以允许组件获取该数据。

一种常见的方法,也是我现在通常使用的方法,是让应用程序中的每个组件仅依赖 props 来获取全局应用程序状态,然后决定 (1) 通过将它们包装在其中将它们直接连接到通量是否更有意义一个容器,或 (2) 允许从某个父容器传递 Prop 。

您可以使用一些抽象来使其中一些技术更加可行。例如,Facebook 开发人员在 a comment on Hacker News 中有这样的说法。 :

Now all your data is in stores, but how do you get it into the specific component that needs it? We started with large top level components which pull all the data needed for their children, and pass it down through props. This leads to a lot of cruft and irrelevant code in the intermediate components. What we settled on, for the most part, is components declaring and fetching the data they need themselves, except for some small, more generic components. Since most of our data is fetched asynchronously and cached, we've created mixins that make it easy to declare which data your component needs, and hook the fetching and listening for updates into the lifecycle methods (componentWillMount, etc).

关于javascript - 将商店状态作为 Prop 传递,还是每个组件访问全局商店?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26563933/

相关文章:

javascript - 检查 Jest 中数组不包含虚假值

reactjs - Redux 操作不调用 reducer

javascript - Firefox 29.0.1 WebSocket 问题

javascript - 将连接的 Gulp 流 file.contents 管道连接到服务器(connect、express 或 http)响应

reactjs - React 是否需要在其 OnChange 事件中重新渲染文本框

javascript - 如何在 react 中创建文本框

javascript - 在 ReactJS 中调用渲染内部的操作 - 无法在调度中间调度

javascript - React + flux : can action return a value?(例如最后创建的 id)

javascript - jQuery 表单验证 - 如何迭代

javascript - 如何避免reactjs索引中的复杂层次结构