React状态变更重渲染性能优化及key props作用解析
Hey 👋,这两个问题都是React性能优化里的核心点,我来给你捋清楚:
1. 当状态变化时,React如何提升重渲染性能?
React主要靠这几个核心机制和优化手段来减少不必要的重渲染:
- 虚拟DOM + Diff算法:React不会直接操作真实DOM,而是先在内存里维护一份虚拟DOM(JS对象)。当状态变化时,它会对比新旧虚拟DOM的差异,只把变化的部分同步到真实DOM,避免了整棵DOM树的重新渲染,这是最基础的性能保障。
- 组件重渲染控制:
- 类组件可以用
PureComponent(自动浅比较props和state)或者手动实现shouldComponentUpdate方法,判断组件是否需要更新; - 函数组件则可以用
React.memo包裹,实现类似PureComponent的浅比较效果,阻止props没变化时的重渲染。
- 类组件可以用
- 缓存计算与函数引用:用
useMemo缓存复杂计算的结果,避免每次重渲染都重复计算;用useCallback缓存函数引用,防止因为函数引用变化导致子组件不必要的重渲染。 - 状态粒度拆分:尽量把状态拆分成更小的独立单元,只让依赖该状态的组件更新,而不是让整个父组件连带所有子组件都重渲染。
2. key属性提升重渲染性能的作用原理
先给你说清楚React渲染列表的逻辑:当你用map渲染列表时,React需要知道每个列表项的“身份”,这样在列表发生变化(增删改、排序)时,才能准确判断哪些项是新增的、哪些是删除的、哪些只是位置变了。
key的核心作用:
- 唯一标识列表项:key是React用来识别每个列表元素的唯一标识,它必须是稳定、唯一的(不能随列表变化而改变)。
- 优化Diff过程:没有key的时候,React会默认用元素在列表中的索引来做标识,但如果列表顺序变化(比如删除中间项、排序),索引会跟着改变,React会误以为后面的所有元素都变了,从而重新渲染这些元素,这就造成了不必要的性能浪费,甚至可能导致组件状态混乱。
举个例子:假设你有个列表[A,B,C],索引是0、1、2。如果你删除B,变成[A,C],索引变成0、1。没有key的话,React会认为原来的C(索引2)被删除了,然后把原来的A(索引0)保留,把原来的C改成现在的C(索引1)——这其实是没必要的,因为C本身没变化,只是位置变了。但如果用每个项的唯一id当key,React就能直接识别出B被删除了,A和C只是位置没变,不需要重新渲染它们。
关于你示例代码里的小问题:
你示例中用了key={i}(索引当key),这种方式只适合列表不会发生顺序变化、不会增删项的场景。如果你的列表有排序、添加删除操作,最好用数据本身的唯一标识,比如示例里的person.id,改成key={person.id}才是更稳妥的做法。
修正后的示例代码:
import React from 'react'; class App extends React.Component { constructor() { super(); this.state = { data: [ { "id":1, "name":"Foo", "age":"20" }, { "id":2, "name":"Bar", "age":"30" }, { "id":3, "name":"Baz", "age":"40" } ] } } render() { return ( <div> <Header/> <table> <tbody> {this.state.data.map((person) => <TableRow key = {person.id} data = {person} />)} </tbody> </table> </div> ); } } class Header extends React.Component { render() { return ( <div> <h1>Header</h1> </div> ); } } class TableRow extends React.Component { render() { return ( <tr> <td>{this.props.data.id}</td> <td>{this.props.data.name}</td> <td>{this.props.data.age}</td> </tr> ); } } export default App;
内容的提问来源于stack exchange,提问作者hatellla
相关产品推荐
相关产品推荐

