React Context API 似乎要重新渲染每个组件

Posted

技术标签:

【中文标题】React Context API 似乎要重新渲染每个组件【英文标题】:React Context API Seems to re-render every component 【发布时间】:2018-12-16 10:45:24 【问题描述】:

我正在尝试在我的应用程序中使用新的 Context API,看起来每次我更新上下文时,它都会重新渲染连接到它的任何组件。我有一个沙盒演示设置来查看代码和工作问题。当您输入输入时 - 呈现按钮上下文,反之亦然。我最初的想法是,如果您输入输入,则只会打印出输入上下文。

DEMO

这是它的工作原理还是我错过了什么? 谢谢, 斯宾塞

【问题讨论】:

我不确定我是否正确理解了这个问题,但所有依赖于此上下文的组件都会重新呈现。它被称为主题上下文。如果您更新主题,您会期望所有主题组件都会更新。 啊——好的。因此,如果我不希望在文本更改时重新渲染按钮,那么它们是否需要拥有自己的“CONTEXT API”?我来自 redux,所有东西都在商店里,当一个项目发生变化时,整个商店不会在每个连接的组件中传播 are-render。 是的,不同的上下文。如果您需要对此类“商店”进行更多控制,Redux 可能是更好的选择。 【参考方案1】:

我避免使用 react context API 重新渲染的方式:

首先我把我的组件写成纯函数式组件:

const MyComponent = React.memo((
    somePropFromContext,
    otherPropFromContext, 
    someRegularPropNotFromContext  
) => 
    ... // regular component logic
    return(
        ... // regular component return
    )
);

然后我写了一个函数来从上下文中选择道具:

function select()
  const  someSelector, otherSelector  = useContext(MyContext);
  return 
    somePropFromContext: someSelector,
    otherPropFromContext: otherSelector,
  


我有我的连接 HOC 写道:

function connect(WrappedComponent, select)
  return function(props)
    const selectors = select();
    return <WrappedComponent ...selectors ...props/>
  

大家一起

import connect from 'path/to/connect'

const MyComponent ... //previous code

function select() ... //previous code

export default connect(MyComponent, select)

用法

<MyComponent someRegularPropNotFromContext=something />

演示

Demo on codesandbox

结论

MyComponent 仅当 context 中的 specifics props 更新为新值时才会重新渲染,如果值相同,则不会重新渲染。它还避免在MyComponent 中未使用的上下文中重新渲染任何其他值。每次上下文更新时,select 中的代码都会执行,但由于它什么都不做,没关系,因为不会浪费 MyComponent 的重新渲染。

【讨论】:

这不违背 Context API 应该做的事情吗?还不如使用 Redux,因为您正在创建自己的“连接”功能......通过添加连接器仍然存在两个问题:Wrapper Hell 和 Props Drilling 佩德罗斯之战 给我错误:React Hook "..." 在函数 "select" 中被调用,它既不是 React 函数组件也不是自定义 React Hook 函数 @HasanSefaOzalp 你可能做错了什么,可能没有在你使用它的地方导入选择函数。 这是一些解决方案,但没有回答问题。答案是无论如何它都不会将任何组件从提供者转移到消费者。【参考方案2】:

这是预期的行为。当提供者数据更新时,作为消费者的组件会重新呈现。此外,shouldComponentUpdate 钩子不适用于消费者。

引用 React 的内容 API:

只要 Provider 的 value 属性发生变化,所有作为 Provider 后代的 Consumer 都会重新渲染。从 Provider 到其后代 Consumer 的传播不受 shouldComponentUpdate 方法的约束,因此即使祖先组件退出更新,Consumer 也会更新。

更多信息请查看here

【讨论】:

谢谢 - 所以基于此 - 我必须需要第二个上下文 api,以便在文本更改时不会重新渲染按钮...... 或者你可以使用shouldComponentUpdate()钩子来决定是否需要重新渲染。这应该可以解决您的问题吧? 好的,这确实有所帮助,但并没有完全达到我的预期,但这确实有助于解决很多问题。出于某种原因,我只是希望它更像 Redux。谢谢! 我刚刚更新了我的答案。如果您认为我的回答是正确的,请随时接受它 再次感谢。我最终在 redux 中编写它只是为了达到同一点哈哈。但是在深入了解上下文 API 的本质的过程中,我学到了很多东西。 ShouldComponentUpdate 在获得类似于 Redux 的行为渲染方面提供了巨大帮助——尽管 Redux 是免费的——但很高兴知道这一点。干杯

以上是关于React Context API 似乎要重新渲染每个组件的主要内容,如果未能解决你的问题,请参考以下文章

React Context API 并避免重新渲染

新的 React Context API 会触发重新渲染吗?

React (Native) Context API 导致 Stack Navigator (React Navigation 5) 在状态更新后重新渲染

React Context 中的函数和重新渲染

React Context Provider 所有子级重新渲染

React 16 的 Portal API 是否要取代 Context API?