【问题标题】:How to reduce react context hell?如何减少反应上下文地狱?
【发布时间】:2021-07-31 17:00:20
【问题描述】:

我继承了一个代码库,之前的所有者在该代码库中广泛使用了 React.Context。这导致了可能被描述为“上下文地狱”的情况

<AppContextProvider>
  <AnotherProvider>
    <AgainAnotherProvider configProp={false}>
      <TestProvider>
        <FooProvider>
          <BarProvider configHereAlso={someEnvronmentVar}>
            <BazProvider>
              <BatProvider>
                <App />
              </BatProvider>
            </BazProvider>
          </BarProvider>
        </FooProvider>
      </TestProvider>
    </AgainAnotherProvider>
  </AnotherProvider>
</AppContextProvider>;

这感觉像是一种反模式,在理解整个应用程序的工作方式时会造成相当大的认知开销。

我该如何解决这个问题?是否可以只使用一个提供者来处理所有事情?我之前使用 redux-toolkit 和 redux 来管理 React 中的状态。上下文有什么类似的吗?

【问题讨论】:

  • 你可以使用一个提供者来处理所有事情,这会让事情变得非常复杂,但我猜这就是原始编码人员试图阻止使用大量定制上下文来向应用程序传递状态的原因。我建议您在进行任何重大更改之前花一些时间了解这里发生的情况。
  • 你的反对纯粹是对句法深度缩进的反对吗?使用这样的上下文不会影响应用程序的性能,事实上恰恰相反。因为&lt;App&gt; 组件本身应该是纯的,所以这个树永远不会重新渲染,并且只有来自应用程序内部的调度才会重新渲染特定的上下文提供者(以及它们的所有消费者,因为它应该),跳过重新渲染嵌套在其中的上下文提供程序。
  • 也许是妥协:如何消除深度嵌套的 React 上下文地狱?虽然......我的意思是,规范的解决方案非常简单:结合上下文。
  • @DaveNewton 不同意您建议的规范解决方案。组合上下文会降低性能。对所提供值的专门更改将重新呈现比必要更多的消费者。在这方面,将上下文分开有一个非常明显的好处。不过标题建议很好。
  • @PatrickRoberts 我并没有说它在所有情况下都是好的解决方案,我说“消除深度嵌套上下文的方法是组合上下文”。它是否“好”取决于上下文。

标签: javascript reactjs react-context react-state-management


【解决方案1】:

我找到了elegant solution

const Providers = ({providers, children}) => {
  const renderProvider = (providers, children) => {
    const [provider, ...restProviders] = providers;
    
    if (provider) {
      return React.cloneElement(
        provider,
        null,
        renderProvider(restProviders, children)
      )
    }

    return children;
  }

  return renderProvider(providers, children)
}

ReactDOM.render(
  <Providers providers={[
    <FooContext.Provider value="foo" />,
    <BarContext.Provider value="bar" />,
    <BazContext.Provider value="baz" />,
  ]}>
    <App />
  </Providers>,
  document.getElementById('root')
);

【讨论】:

  • 请在您的回答中描述为什么您认为它是一个优雅的解决方案,以及与 OP 相比,该解决方案所代表的“什么”
  • 在这个解决方案中,需要子组件的组件存在问题,例如在 TS 中这有时无法通过。
【解决方案2】:

摆脱额外上下文的一种方法是向上下文提供的值添加更多变量。

例如,如果有两个上下文 UserContextProfileContext 提供者如下:

&lt;UserContext.Provider value={user}...

&lt;ProfileContext.Provider value={profile}...

然后您可以将它们合并到一个上下文中:

&lt;UserProfileContext.Provider value={{user, profile}}...

注意:这并不意味着您应该将所有上下文合并到一个上下文中,因为关注点是分离的,并且当上下文的值更改导致不需要的渲染时,所有使用者都会重新渲染。

【讨论】:

  • 另外,请记住,仅当必须在许多地方和/或树的深处使用该值时,才应使用上下文。否则,只需将值作为属性传递。
  • 请不要在没有意识到对您的应用性能造成的后果的情况下这样做。我建议你阅读这篇总结得很好的文章:thoughtspile.github.io/2021/10/04/react-context-dangers
猜你喜欢
  • 2021-01-16
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 2019-09-26
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多