React 避免组件重复渲染,通常是最重要的代码层面的前端优化手段之一,关键在于开发者对应用的关键之处进行特殊处理,比如父组件状态更新导致无关的子组件重新渲染,从而避免 React
reconciler调和昂贵的性能开销。
栗子
一个具有状态的列表,子组件ListItem的事件出发之后,会导致父组件状态listData变更。
import React from "react";
const initListData = Array.from(Array(10), (v, i) => {
return { text: i, id: i };
});
// Chidren
const ListItem = ({ text, id, onRemove }) => {
console.log("listitem");
return (
<li>
<span>{text}</span>
<button onClick={() => onRemove(id)}>删除</button>
</li>
);
};
// Parent
export default class App extends React.Component {
state = {
listData: initListData
};
handleRemove = (id) => {
const { listData } = this.state;
this.setState({ listData: listData.filter((v, k) => v.id !== id) });
};
render() {
const { listData } = this.state;
return (
<ul>
{listData.map(({ text, id }, index) => (
<ListItem key={id} id={id} text={text} onRemove={(id) => this.handleRemove(id)} />
))}
</ul>
);
}
}
1. React.Memo
函数组件写法:当且仅当 text, id, onRemove 改变时,子组件触发重新渲染。
const ListItem = React.memo(({ text, id, onRemove }) => {
console.log("listitem");
return (
<li>
<span>{text}</span>
<button onClick={() => onRemove(id)}>删除</button>
</li>
);
});
2. React.PureComponent
类组件写法:当且仅当 text, id, onRemove 改变时,子组件触发重新渲染。
class ListItem extends React.PureComponent {
render() {
const { text, id, onRemove } = this.props;
console.log("listitem");
return (
<li>
<span>{text}</span>
<button onClick={() => onRemove(id)}>删除</button>
</li>
);
}
}
3. shouldComponentUpdate
类组件写法:当且仅当 text, id, onRemove 改变时,子组件触发重新渲染。
class ListItem extends React.Component {
shouldComponentUpdate(preprops, nextprops) {
// deep diff
}
render() {
const { text, id, onRemove } = this.props;
console.log("listitem");
return (
<li>
<span>{text}</span>
<button onClick={() => onRemove(id)}>删除</button>
</li>
);
}
}
4. JSX 中移除箭头函数
由于箭头函数会生成新的引用,
避免使用箭头函数 onRemove={(id) => this.handleRemove(id)}
<ListItem key={id} id={id} text={text} onRemove=(id) => this.handleRemove(id)} />
推荐使用类属性 onRemove={this.handleRemove}
<ListItem key={id} id={id} text={text} onRemove={this.handleRemove} />