React Context API意外重渲染疑问及代码优化咨询
React Context 重渲染与Provider使用问题解答
一、关于Provider重渲染的疑问
- 「每次Provider重渲染」指什么?
这里的Provider特指Context.Provider这个React内置组件的重渲染。当它的value属性变化,或者它的父组件发生重渲染时,这个Provider组件就会重新渲染。 - 此处的Provider是否指示例中的App组件?
不是。示例里的App是包裹Provider的父组件,App重渲染会带动Provider跟着重渲染,但Provider本身的重渲染也可能由自身value变化触发。 - App组件内部子组件变化会触发App重渲染吗?
不会。React组件的重渲染是自上而下的,子组件的state或props变化只会让子组件自己重渲染,不会反向触发父组件(比如App)的重渲染。 - 最外层的App组件何时重渲染?
App组件重渲染的场景包括:- 自身的state发生更新
- 接收的props发生变化(比如Next.js中
_app.tsx的pageProps更新) - 存在上层包裹组件时,上层组件重渲染带动它(通常App是最外层,这种情况很少)
- 调用了
forceUpdate这类强制重渲染的API(不推荐使用)
二、Next.js _app.tsx中Context Provider的value处理
你当前的写法会导致每次_app.tsx重渲染时,都生成一个全新的{onTooManyRequests: ...}对象——因为对象是每次渲染时重新声明的,这会让所有订阅这个Context的组件都触发不必要的重渲染,哪怕setShowTooManyRequestsModal对应的状态根本没变化。
必须优化这个写法,有两种常用方案:
方案1:用useState存储value
const [contextValue] = useState({ onTooManyRequests: () => setShowTooManyRequestsModal(true), }); return ( <TooManyRequestsContext.Provider value={contextValue}> {/* ... 你的组件 ... */} </TooManyRequestsContext.Provider> );
state的初始值只会在组件首次渲染时创建一次,后续重渲染时不会生成新对象,除非手动更新这个state。
方案2:用useMemo缓存value
const contextValue = useMemo(() => ({ onTooManyRequests: () => setShowTooManyRequestsModal(true), }), []); // 空依赖数组,只会在首次渲染时生成一次对象 return ( <TooManyRequestsContext.Provider value={contextValue}> {/* ... 你的组件 ... */} </TooManyRequestsContext.Provider> );
useMemo会根据依赖项缓存值,这里依赖为空,所以对象只会生成一次,彻底避免因引用变化导致的意外重渲染。更推荐这个方案,逻辑更清晰,不需要额外维护state。
内容的提问来源于stack exchange,提问作者Florian Walther
相关产品推荐
相关产品推荐

