HOW - React 组件渲染受其他无关数据影响和优化方案(含memo和props.children)
目录
- 背景
- 优化方案
- 方法一:提取到父组件,分离 Timer 和 OtherSlowComponent
- 方法二:使用 useMemo 缓存慢组件(更适用于传了 props 的场景)
- 方法三:memo
- 方法四:props.children
- 为什么 props.children 能帮助优化
- 示例:使用 props.children 优化重渲染
- 渲染优化分析
- 总结
背景
有如下组件:
const Timer = () => {
const [time, setTime] = useState(0); // 每秒更新
return (
<>
<h1>当前时间:{dayjs(time).format("YYYY-MM-DD HH:mm:ss")}</h1>
<OtherSlowComponent /> // 每次 setTime 都会触发整个组件重新渲染,包括这里
</>
);
};
const Container = () => <Timer />;
每秒更新一次 time,导致整个 Timer 组件重新渲染,连带 ·OtherSlowComponent· 也每秒被重新渲染一次,哪怕它跟时间无关!
又或者:
import { memo } from 'react';
export const App = () => {
const { currentUserInfo, users } = useGetInfoData();
return (
<div className="App">
<CurrentUserInfo data={currentUserInfo} />
<UserInfoList users={users} />
</div>
);
};
假如 currentUserInfo 更新,也会导致 UserInfoList 组件的重新渲染。
优化方案
方法一:提取到父组件,分离 Timer 和 OtherSlowComponent
const Container = () => {
return (
<>
<Timer />
<OtherSlowComponent />
</>
);
};
如果 OtherSlowComponent
和 Timer
没有任何依赖关系,直接将它们并列在父组件中是最简单高效的做法,彻底避免无意义的重渲。
方法二:使用 useMemo 缓存慢组件(更适用于传了 props 的场景)
const memoizedSlowComp = useMemo(() => <OtherSlowComponent />, []);
但注意:useMemo
仅在初次渲染创建,依赖项变化时才会重新计算。
方法三:memo
export const App = () => {
const { currentUserInfo, users } = useGetInfoData();
return (
<div className="App">
<CurrentUserInfo data={currentUserInfo} />
<UserInfoList users={users} />
</div>
);
};
const UserInfoList = memo(({ users }) => {
// ...
});
方法四:props.children
为什么 props.children 能帮助优化
如果你把慢组件 OtherSlowComponent
作为 children
传进去,并且 Timer 本身不关心它、也不依赖它的任何状态变化,那就可以很好地“托管”渲染时机 —— 只要父组件不变,它不会重渲!
示例:使用 props.children 优化重渲染
const Container = () => {
return (
<Timer>
<OtherSlowComponent />
</Timer>
);
};
const Timer = ({ children }: { children: React.ReactNode }) => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => setTime(new Date()), 1000);
return () => clearInterval(intervalId);
}, []);
return (
<>
<h1>当前时间: {dayjs(time).format("YYYY-MM-DD HH:mm:ss")}</h1>
{children}
</>
);
};
const OtherSlowComponent = React.memo(() => {
console.log('💡 OtherSlowComponent 渲染了');
return <div>这是一个渲染慢的组件</div>;
});
渲染优化分析
组件 | 是否每秒重渲染? | 原因 |
---|---|---|
Timer | ✅ | 每秒更新 time |
OtherSlowComponent | ❌ | 被当作 children 静态传入,不受 time 影响,且 React.memo 避免重渲染 |
更多关于 props.children 的内容可以阅读 WHAT - React 组件的 props.children 属性
总结
方法 | 是否推荐 | 说明 |
---|---|---|
使用 props.children | ✅✅✅ | 非常推荐,结构清晰、性能佳 |
React.memo 搭配 children | ✅ | 更加保险,确保不被不必要的重渲染触发 |
放到父组件里 | ✅ | 如果结构允许,这是最清晰的做法 |