在 React 中避免不必要的重新渲染
构建高性能 React 应用程序的关键之一是避免不必要的重新渲染。React 的渲染引擎是高效的,但防止在不需要的地方重新渲染仍然至关重要。在这篇文章中,我们将介绍常见错误以及如何避免它们。
1. 使用 React.memo
缓存组件
React.memo
帮助你在组件的 props 没有改变时跳过重新渲染。但是,如果不实现自定义比较函数,很容易滥用 React.memo
。
不正确的用法:
const MemoizedComponent = React.memo(MyComponent);
这只检查 props 引用是否发生了变化,这可能并不总是足够的。
正确用法:
const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => {
return prevProps.itemId === nextProps.itemId;
});
在这里,我们使用了一个自定义的比较函数,它只在 itemId
prop 发生变化时触发重新渲染。
2. 避免过度使用内联函数
在 JSX 中使用内联函数可能会导致不必要的重新渲染,因为 React 在每次渲染时都会将新函数视为新 prop。
不正确的用法:
function ButtonComponent() {
return <button onClick={() => handleClick()}>Click me</button>;
}
这会导致在每次渲染时重新创建 handleClick
,从而导致不必要的重新渲染。
正确用法:
import { useCallback } from 'react';
function ButtonComponent() {
const handleClick = useCallback(() => {
// Handle click logic
}, []);
return <button onClick={handleClick}>Click me</button>;
}
通过使用 useCallback
,我们记住了 handleClick
函数,防止了每次渲染时不必要的重新创建。
3. 利用 PureComponent
当使用类组件时,使用 React.PureComponent
可以确保组件仅在其 props 或 state 发生变化时重新渲染。如果你使用的是 React.Component
,可能会导致不必要的重新渲染。
不正确的用法:
class CardComponent extends React.Component {
// Component logic
}
正确用法:
class CardComponent extends React.PureComponent {
// Component logic
}
通过扩展 React.PureComponent
将浅层比较 props 和 state,避免不必要的重新渲染。
4. 优化功能组件中的 useSelector
当从 react-redux
使用 useSelector
时,只选择必要的 state 切片很重要。
不正确的用法:
import { useSelector } from 'react-redux';
const DataComponent = () => {
const globalState = useSelector((state) => state);
// Render logic
};
这将导致组件在状态的任何部分发生变化时重新渲染。
正确用法:
import { useSelector } from 'react-redux';
const DataComponent = () => {
const selectedData = useSelector((state) => state.specificSlice);
// Render logic based on specific slice
};
通过仅选择状态的必要部分,可以最大限度地减少重新渲染。
5. 在类组件中实现 shouldComponentUpdate
对于不扩展 PureComponent
的类组件,手动实现 shouldComponentUpdate
可以更精细地控制组件何时重新渲染。
不正确的用法:
class ListItem extends React.Component {
// Component logic
}
这将在每次父组件渲染时重新渲染,即使 props 和 state 没有改变。
正确用法:
class ListItem extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return this.props.itemId !== nextProps.itemId || this.state.value !== nextState.value;
}
// Component logic
}
通过自定义 shouldComponentUpdate
,我们确保组件仅在 itemId
prop 或 value
状态发生变化时重新渲染。