你有没有遇到过这种情况:点开一个网页,按钮点了半天没反应,列表滚动卡得像幻灯片,刷新一下又好了?其实很多时候,问题就出在React组件的渲染效率上。别以为这只是程序员才该操心的事,用起来卡,体验差,谁用谁知道。
为什么React组件会变慢?
React本身设计得很高效,靠虚拟DOM减少页面重绘。但如果你写的组件一更新就“全家桶”跟着重刷,那再快的框架也扛不住。比如你有个购物车页面,商品列表很长,每次你点个加减数量,整个列表都抖一下——这大概率是组件没控制好更新范围。
不必要的重新渲染
最常见的问题是父组件一更新,所有子组件不管用不用到新数据,全跟着重新跑一遍render。就像你换了个灯泡,结果家里每个电器都重启一次,太离谱了。
解决办法之一是用 React.memo 包一层,让组件只在props变化时才更新:
const ProductItem = React.memo(({ name, price }) => {
return <div>{name}: {price}元</div>;
});
这样哪怕父组件刷新,只要这个商品的数据没变,它就不动。
频繁创建函数或对象
有时候你在组件里直接写内联函数,看着省事,实际每次render都会生成新函数,导致被memo的子组件收不到稳定的props,又白搭了。
比如这样写就有问题:
{products.map((p) =>
<ProductItem
key={p.id}
data={p}
onClick={() => console.log(p.id)}
/>
)}
每次渲染都会新建onClick函数。应该用 useCallback 缓存它:
const handleClick = useCallback((id) => {
console.log(id);
}, []);
{products.map((p) =>
<ProductItem
key={p.id}
data={p}
onClick={() => handleClick(p.id)}
/>
)}
大数据量别硬来
如果要展示几百上千条数据,比如聊天记录、订单历史,别一股脑全render出来。人眼能看清的就那么几行,剩下的都在白忙活。
这时候可以用“虚拟滚动”,只渲染可视区域内的元素。像 react-window 这类库就是干这个的,滚动几千条数据也顺滑。
拆分大组件
一个组件塞太多逻辑,又是表单又是列表还得实时更新状态,自然容易卡。就像厨房里一个人又要切菜又要炒菜还要端盘子,忙不过来。
把功能拆开,各司其职。表单归表单,列表归列表,用状态提升或context传递必要数据,各自独立更新,互不干扰。
性能问题不像bug那样一眼看出,但它悄悄影响着每个人的操作体验。代码写得巧一点,用户手指头就轻松一大截。