React使用条件渲染与children prop时如何避免子组件重渲染
悬停父组件触发子组件重渲染问题修复
问题场景
有一个复用了大部分通用逻辑的组件,需要解决鼠标悬停父组件时子组件意外重渲染的问题,初始实现代码如下:
const ReusableComponent = ({ conditional }) => { const [isHovered, setIsHovered] = useState(false); const AnotherReusableComponent = ({ children }) => ( <div>{children}</div> ); const renderComponent = () => { if (conditional) { return <ComponentA />; }; return <ComponentB />; }; return ( <div> <title onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > Menu </title> <div className={isHovered ? 'oneClass' : 'otherClass'}> <AnotherReusableComponent> {renderComponent()} </AnotherReusableComponent> </div> </div> ); }
已知信息
ComponentA和ComponentB根据外层className值控制显示与隐藏- 悬停事件用于切换className的取值
- 已尝试使用
memo进行优化,但没有生效 - 重渲染行为仅在触发悬停事件时发生
根本原因
memo失效的核心原因是在ReusableComponent的渲染函数内部定义了AnotherReusableComponent组件和renderComponent方法:
- 每次
isHovered变化触发父组件重渲染时,这两个声明都会重新执行,生成完全新的引用 - React判定组件类型变化时,会直接卸载旧组件、重新挂载新组件,
memo的浅比较逻辑根本不会触发,自然无法生效
修复方案
- 将渲染函数内部定义的子组件移到组件外部,保证组件引用稳定
- 移除不必要的内部渲染函数,直接在JSX中写条件渲染逻辑,避免函数引用变化带来的重渲染
- 给需要缓存的子组件包裹
memo,此时props不变时就不会触发重渲染
修复后的代码:
import { useState, memo, useCallback } from 'react'; // 移到父组件外部,保证引用稳定 const AnotherReusableComponent = ({ children }) => ( <div>{children}</div> ); // 子组件包裹memo实现渲染缓存 const MemoComponentA = memo(ComponentA); const MemoComponentB = memo(ComponentB); const ReusableComponent = ({ conditional }) => { const [isHovered, setIsHovered] = useState(false); // 事件函数用useCallback缓存,避免每次渲染生成新引用 const handleMouseEnter = useCallback(() => setIsHovered(true), []); const handleMouseLeave = useCallback(() => setIsHovered(false), []); return ( <div> <title onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} > Menu </title> <div className={isHovered ? 'oneClass' : 'otherClass'}> <AnotherReusableComponent> {conditional ? <MemoComponentA /> : <MemoComponentB />} </AnotherReusableComponent> </div> </div> ); }
内容的提问来源于stack exchange,提问作者ricardowgomes
相关产品推荐
相关产品推荐

