使用React.memo与useCallback阻止InputWithLabel组件重渲染失效问题
问题原因
React.memo 默认对组件的 props 做浅比较,只要有任意一个 props 发生引用层面的变化,就会触发组件重渲染。你点击 Dismiss 触发 App 组件重渲染时,传给 InputWithLabel 的 props 中:
id、value(点击Dismiss时searchTerm无变化)、onInputChange(已用useCallback缓存)、isFocused都是稳定不变的- 唯一变化的是
children属性:你直接在组件中写的<strong>Search:</strong>会在每次 App 渲染时生成一个全新的 React 元素对象,引用和上一次渲染的不一样,因此浅比较不通过,触发重渲染。
解决方法
有两种常用方案可选:
方案1:缓存固定的 children 内容
在 App 组件中用 React.useMemo 把固定不变的标签内容缓存起来,保证每次渲染的 children 引用一致:
const App = () => { // ...其余原有代码不变 // 依赖数组为空表示该值永远不会重新计算 const searchLabel = React.useMemo(() => <strong>Search:</strong>, []); return ( <div> <h1>My Hacker Stories</h1> <InputWithLabel id="search" value={searchTerm} isFocused onInputChange={handleSearch} > {searchLabel} </InputWithLabel> {/* ...其余原有代码不变 */} </div> ) }
方案2:给 React.memo 自定义比较逻辑
如果你能确定 children 永远不会变化,可以给 React.memo 传入第二个参数,自定义 props 比较规则,跳过对 children 的比较:
const InputWithLabel = React.memo( // 原有组件定义保持不变 ({ id, value, type = 'text', onInputChange, isFocused, children, }) => { // ...组件内部原有逻辑不变 }, // 自定义比较函数,返回true表示props无变化,不需要重渲染 (prevProps, nextProps) => { return ( prevProps.id === nextProps.id && prevProps.value === nextProps.value && prevProps.type === nextProps.type && prevProps.onInputChange === nextProps.onInputChange && prevProps.isFocused === nextProps.isFocused ); } );
两种方案都可以实现点击 Dismiss 删除条目时,InputWithLabel 不会发生不必要的重渲染,若后续存在修改children的需求,优先选择方案1更稳妥。
内容的提问来源于stack exchange,提问作者Tan Nguyen
相关产品推荐
相关产品推荐

