类组件中利用 shouldComponentUpdate
优化性能
- 基本概念:
shouldComponentUpdate
是 React 类组件的生命周期方法,它接收新的 props
和 state
作为参数,返回一个布尔值。如果返回 true
,则组件会重新渲染;返回 false
,则组件不会重新渲染。
- 比较特定字段:
- 假设列表项数据在
props
中的 listData
字段,我们可以这样实现 shouldComponentUpdate
:
class ListComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// 只比较 listData 字段
return this.props.listData!== nextProps.listData;
}
render() {
return (
<ul>
{this.props.listData.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
}
- 如果
listData
是一个对象数组,且每个对象有一个 id
字段标识唯一性,我们可以通过比较数组的长度以及每个对象的 id
来决定是否更新:
class ListComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
if (this.props.listData.length!== nextProps.listData.length) {
return true;
}
for (let i = 0; i < this.props.listData.length; i++) {
if (this.props.listData[i].id!== nextProps.listData[i].id) {
return true;
}
}
return false;
}
render() {
return (
<ul>
{this.props.listData.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
);
}
}
函数式组件的替代方案
- React.memo:
React.memo
是一个高阶组件,它对函数式组件进行浅比较优化。
- 例如,对于展示列表的函数式组件:
const ListComponent = React.memo(({ listData }) => {
return (
<ul>
{listData.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
});
- 这里
React.memo
会对 props
进行浅比较,如果 props
中的 listData
引用没有变化,组件不会重新渲染。如果 listData
是对象数组且需要深度比较,可以传递一个自定义比较函数作为第二个参数:
const areEqual = (prevProps, nextProps) => {
if (prevProps.listData.length!== nextProps.listData.length) {
return false;
}
for (let i = 0; i < prevProps.listData.length; i++) {
if (prevProps.listData[i].id!== nextProps.listData[i].id) {
return false;
}
}
return true;
};
const ListComponent = React.memo(({ listData }) => {
return (
<ul>
{listData.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
);
}, areEqual);
- useMemo 和 useCallback:
useMemo
用于缓存计算结果,避免不必要的重新计算。例如,如果列表组件有一些基于 props
计算的派生数据:
const ListComponent = ({ listData }) => {
const derivedData = useMemo(() => {
// 复杂计算逻辑,依赖 listData
return listData.filter(item => item.isActive);
}, [listData]);
return (
<ul>
{derivedData.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
);
};
useCallback
用于缓存函数定义,避免函数在每次渲染时重新创建。如果列表组件传递一个回调函数给子组件,且该回调函数依赖 props
或 state
:
const ListComponent = ({ listData, onItemClick }) => {
const handleClick = useCallback((item) => {
onItemClick(item);
}, [onItemClick]);
return (
<ul>
{listData.map((item, index) => (
<li key={index} onClick={() => handleClick(item)}>{item.name}</li>
))}
</ul>
);
};