大白话React 中React.memo的作用,如何利用它进行组件性能优化?
React.memo 是啥玩意儿
在 React 里,组件渲染是很频繁的事儿。每次父组件状态变了,子组件就可能会重新渲染,哪怕子组件的 props 压根儿没变化。这就好比你去超市,只买了瓶饮料,收银员却把整个货架都重新整理一遍,纯属浪费时间和精力。而 React.memo
就是来解决这个问题的,它能让组件"记着"之前的渲染结果,要是 props 没变化,就直接用之前的结果,不用重新渲染,这样能大大提升性能。
怎么用 React.memo
React.memo
是一个高阶组件,你把它套在你的组件外面,它就会帮你比较前后两次的 props。要是一样,就不重新渲染组件。下面咱来看看具体代码:
javascript
// 导入 React 库,因为要用到 React.memo
import React from 'react';
// 定义一个简单的组件,这个组件接收一个 name 属性
const MyComponent = React.memo((props) => {
// 打印日志,方便我们知道组件什么时候渲染了
console.log('MyComponent 渲染了');
// 返回一个简单的 JSX 元素,显示传入的 name 属性
return <div>Hello, {props.name}!</div>;
});
// 定义一个父组件
const ParentComponent = () => {
// 定义一个状态变量 count,初始值为 0
const [count, setCount] = React.useState(0);
// 定义一个函数,用于增加 count 的值
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
{/* 显示 count 的值 */}
<p>Count: {count}</p>
{/* 点击按钮,调用 handleClick 函数增加 count 的值 */}
<button onClick={handleClick}>增加计数</button>
{/* 使用 MyComponent 组件,传入 name 属性 */}
<MyComponent name="World" />
</div>
);
};
// 导出父组件,方便在其他地方使用
export default ParentComponent;
代码解释
-
MyComponent
组件:- 这是一个简单的函数组件,接收一个
name
属性。 - 用
React.memo
把它包起来,这样当MyComponent
的props
没变化时,就不会重新渲染。 - 里面有个
console.log
,每次渲染都会打印日志,方便我们观察。
- 这是一个简单的函数组件,接收一个
-
ParentComponent
组件:- 有个
count
状态变量,初始值是 0。 - 有个按钮,点击后会调用
handleClick
函数,让count
的值加 1。 - 里面使用了
MyComponent
组件,传入name
属性为World
。
- 有个
使用场景
- 纯展示组件 :如果一个组件只是根据传入的
props
来展示内容,没有自己的状态,也不做什么副作用操作,那就可以用React.memo
包起来。比如上面的MyComponent
,它只根据name
属性来显示内容。 - 频繁渲染的组件 :要是一个组件在父组件每次渲染时都会跟着渲染,但它的
props
大部分时间都不变,那就用React.memo
优化一下。比如列表里的每个列表项组件。
注意事项
React.memo
只比较props
的浅层次变化。要是props
里有对象或者数组,而且这些对象或数组的引用变了,哪怕里面的值没变,组件也会重新渲染。- 要是你需要自定义比较逻辑,可以给
React.memo
传入第二个参数,它是一个函数,用来比较前后两次的props
。
jsx
// 自定义比较函数
const areEqual = (prevProps, nextProps) => {
// 这里可以写自定义的比较逻辑
return prevProps.name === nextProps.name;
};
// 使用自定义比较函数的 MyComponent
const MyComponentWithCustomCompare = React.memo((props) => {
console.log('MyComponentWithCustomCompare 渲染了');
return <div>Hello, {props.name}!</div>;
}, areEqual);
这样,你就可以根据自己的需求来控制组件是否重新渲染啦。