React Redux:更多容器与更少容器

问题描述 投票:16回答:4

随着我进一步实现redux +反应到一个相当复杂的应用程序,这依赖于加载单个页面的许多API请求,我无法确定在页面的根处有一个容器组件是否更好处理所有异步的东西,并将道具传递给哑组件,与多个容器组件相关,这些组件只关注他们需要的数据,以及获取他们需要的数据。 我在这两种模式之间来回走动,发现它们各有利弊:

如果我在顶部放置一个容器组件:

  • pro:所有isFetching props和fetchSomeDependency()动作都可以在一个地方处理。
  • con:真正令人讨厌的缺点是我发现自己不得不通过多个组件转发道具和回调,而树中间的某些组件最终会与此绑定。

这是一个问题的视觉示例,显示了道具所需的关系:

<MyContainer
  data={this.props.data}
  isFetchingData={this.props.isFetchingData}
  fetchData={this.props.fetchData}
 >
   {!isFetchingData && 
     <MyModal
        someData={props.data}
        fetchData={props.fetchData}
      >
       <MyModalContent
         someData={props.data}
         fetchData={props.fetchData}
       >
          <SomethingThatDependsOnData someData={props.someData} />
          <SomeButtonThatFetchesData  onClick={props.fetchData} />
        </MyModalContent>
      </MyModal>
    }
 </MyContainer>

正如你所看到的, <MyModal /><MyModalContent />现在需要关注与它无关的道具,因为模态应该能够重复使用并且只关注风格的质量。模态。

起初上面看起来很棒,但是一旦我有100多个组件,它们都感觉非常纠结,我发现这些顶级容器组件的复杂性太高,我不喜欢,看到他们中的大多数(在应用程序中我“正在努力”取决于3个以上API请求的响应。

然后我决定尝试多个容器:

  • 亲:完全不需要转发道具。 在某些情况下这样做仍然有意义,但它更灵活。
  • 亲:更容易重构的方式。 我很惊讶我如何能够在没有任何破坏的情况下显着移动和重构组件,而在其他模式中,事情已经破坏了很多。
  • 亲:每个容器组件的复杂性要小得多。 我的mapStateToPropsmapDispatchToProps更具体到它所在组件的用途。
  • con:任何依赖于异步内容的组件总是需要处理isFetching状态。 这增加了在单个容器组件中处理它的模式中不必要的复杂性。

所以主要的困境是,如果我使用一个容器 ,我会在根容器和叶子组件之间的组件中获得这种不必要的复杂性。 如果我使用多个容器 ,我会在叶子组件中获得更多的复杂性,并最终得到需要担心isFetching按钮,即使按钮不应该关注它。

我想知道是否有人找到了避免利弊的方法,如果有的话,你遵循的“经验法则”是什么来避免这种情况?

谢谢!

reactjs redux react-redux
4个回答
2
投票

我一直看到的方法是将容器放在除root / app组件之外的逻辑组件组的最顶层组件中。

因此,如果我们有一个显示结果的简单搜索应用程序,并假设组件heiarchy就是这样

<Root> <- setup the app
  <App>
    <Search/> <- search input
    <Results/> <- results table
  </App>
</Root>

我会使SearchResults redux感知容器。 因为反应组分可以是可组合的 。 您可能有其他组件或页面需要显示ResultsSearch 。 如果将数据获取和存储感知委托给根或应用程序组件,则会使组件变得依赖于彼此/应用程序。 当您必须实施更改时,这会使线路变得更难,现在您必须更改使用它们的所有位置。

例外情况可能是组件之间确实存在紧密耦合的逻辑。 即便如此,我还是会说你应该创建一个包装紧密耦合组件的容器,因为它们不能在没有彼此的情况下实际使用。


2
投票

Redux作者Dan Abramov建议您在需要时使用容器组件。 也就是说,一旦你有太多的道具在组件之间上下布线,就可以使用容器了。

他称之为“正在进行的重构过程”。

请参阅此文章: https//medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0


1
投票

我甚至不会考虑使用单一容器方法。 它几乎完全否定了redux的所有优点。 如果您的所有州都在一个地方并且所有回调都在一个地方(根组件),则无需任何状态管理系统。

不过,我觉得走路很细。 我正在制作一个应用程序,我已经在那里工作了大约5周(兼职),现在它已达到3000行。 它有3个级别的视图嵌套,我自己实现的路由机制,以及需要修改状态的10个以上嵌套级别的组件。 我基本上每个大屏幕都有一个redux容器,它的工作非常棒。

但是,如果我点击我的“客户”视图,我会得到一个很好的客户列表,因为我的客户端视图位于redux容器内,并获取作为props传递的客户列表。 但是,当我点击一个客户端时,我真的很犹豫为个人客户端的配置文件做另一个redux容器,因为它只是一个额外级别的传递道具。 似乎根据应用程序的范围,您可能希望将props返回到redux容器之前的1-2级,如果它不止于此,那么只需创建另一个redux容器。 然后,如果它是一个更复杂的应用程序,那么有时使用redux容器和其他一些不使用它们的混合可能更糟糕的可维护性。 简而言之,我的观点是尽可能地尽量减少redux容器,但绝对不能以复杂的支撑链为代价,因为这是使用redux开始的主要观点。


1
投票

所以我发布这个问题已经有两年多了,而且这一直是我一直在与React / Redux合作。 我的一般经验法则如下: 使用更多容器,但尝试以不需要了解isFetching的方式编写组件。

例如,以下是我之前如何构建待办事项列表的典型示例:

  function Todos({ isFetching, items }) {
    if (isFetching) return <div>Loading...</div>

    return (
      <ul>
        {items.map(item => 
          <li key={item.id}>...</li>
        )}
      </ul>
    )
  }

现在我会做更多的事情:

  function Todos({ items }) {
    if (!items.length) return <div>No items!</div>

    return (
      <ul>
        {items.map(item => 
          <li key={item.id}>...</li>
        )}
      </ul>
    )
  }

这样,您只需连接数据,组件就不会担心异步API调用的状态。

大多数事情都可以这样写。 我很少需要isFetching ,但是当我这样做时通常是因为:

  1. 我需要阻止,例如,第二次单击提交按钮,这会进行API调用,在这种情况下,prop应该被称为disableSubmit而不是isFetching ,或者

  2. 我想在某些东西等待异步响应时显式地显示一个加载器。

现在,您可能会想,“在上面的todos示例中提取项目时,您不想显示加载程序吗?” 但在实践中,实际上我不会。

这样做的原因是,在上面的示例中,假设您正在轮询新的待办事项,或者当您添加待办事项时,您“重新获取”待办事项。 在第一个例子中会发生的事情是,每次发生这种情况时,待办事项都会消失并经常被“正在加载......”取代。

但是,在第二个与isFetching ,只需添加/删除新项目。 在我看来,这是一个更好的用户体验。

实际上,在发布之前,我查看了我编写的交换接口的所有UI代码,这非常复杂,并且没有找到将isFetching连接到我编写的容器组件的单个实例。

© www.soinside.com 2019 - 2024. All rights reserved.