为何你的 React.memo 没有生效?useMemo、useCallback用起来!
当在开发 React 应用程序时,优化性能是一个重要的考虑因素。React 提供了一些优化工具和技术,其中之一就是 React.memo
。React.memo
是一个高阶组件(Higher-Order Component,HOC),用于优化函数组件的渲染性能。
什么是 React.memo
React.memo
是 React 提供的一个函数,用于优化函数组件的渲染性能。它类似于 React.PureComponent
,但适用于函数组件而不是类组件。React.memo
函数接收一个组件作为参数,并返回一个经过优化的新组件。
优化的原理是 React.memo
对组件的输入 props
进行浅比较。它会比较当前渲染时的 props
和前一次渲染时的 props
是否相等。只有当 props
发生变化时,React.memo
才会重新渲染组件;否则,它会使用前一次渲染的结果,从而避免不必要的重渲染。
如何使用
import React from 'react';
const UserProfile = React.memo(({ name, age, avatar }) => {
console.log('Rendering UserProfile');
return (
<div>
<img src={avatar} alt="User Avatar" />
<div>Name: {name}</div>
<div>Age: {age}</div>
</div>
);
});
在这个示例中,UserProfile
是一个纯展示组件,它接收用户的姓名、年龄和头像作为 props
。由于它的渲染结果只依赖于传入的 props
,我们可以使用 React.memo
来优化它。这样,只有当 name
、age
或 avatar
发生变化时,才会重新渲染 UserProfile
组件。
为何你的React.memo没有生效
1. 直接在函数式组件顶层定义引用类型:
如下的代码中,每次count被更新,App都会重新渲染,obj对象和onChanged函数也会被重新声明,所以对于 MyComponent 来说 obj一直在发生变化,导致子组件一直在重复渲染
import React from 'react';
const MyComponent = React.memo((props) => {
console.log('Rendering MyComponent');
return <div>{props.name}</div>;
});
function App() {
const [count, setCount] = React.useState(0);
const handleClick = () => {
setCount(count + 1);
};
const onChanged = ()=>{}
const obj = { value: count };
return (
<div>
<button onClick={handleClick}>Increment Count</button>
<MyComponent name="John" obj={obj} onChanged={onChanged}/>
</div>
);
}
如果要避免重复渲染,需要保持引用不变:
// 缓存对象
const obj = useMemo(() => ({ value: 1 }), []);
// 缓存函数
const onChanged = useCallback(() => {}, []);
2. 直接setState一个新的对象:
如下的代码中,每次执行setObj方法都会被传入一个新对象,它的引用地址发生了变化,所以子组件会重新渲染
import React from 'react';
const MyComponent = React.memo((props) => {
console.log('Rendering MyComponent');
return <div>{props.name}</div>;
});
function App() {
const [obj, setObj] = React.useState({});
const handleClick = () => {
setObj({ a: 3 });
};
return (
<div>
<button onClick={handleClick}>Increment Count</button>
<MyComponent name="John" obj={obj} />
</div>
);
}
如果不想重新渲染,需要保持引用地址不变:
// 直接更改旧值
setObj((old) => {
old.a = 3;
return old;
});
// 缓存对象,仅在发生变化时重新创建新对象,即触发重新渲染
const newObj = useMemo(() => ({ value: count }), [count]);
setObj(newObj)
请注意,React.memo
的比较是浅比较,只比较 props
对象的第一层属性是否发生变化。如果 props
包含复杂的数据结构(如对象或数组),并且其引用没有发生变化,那么 React.memo
无法检测到深层的变化。在这种情况下,需要使用其他方法来确保组件的正确更新。
总之,除了基本类型变化外,你还需要关注你传递的引用类型数据是否发生了变化,从而去判断你的组件是否会被重新渲染。
结论
通过使用 React.memo
,我们可以优化函数组件的渲染性能,避免不必要的重渲染。它通过浅比较 props
对象的方式来决定是否重新渲染组件。然而,需要注意的是,React.memo
的比较是浅比较,只检查第一层属性是否发生变化。
在实际开发中,我们应该根据组件的特性和需求,合理选择使用 React.memo
进行优化。对于纯展示组件和具有大量子组件的组件树,使用 React.memo
可以有效地提升性能和减少不必要的渲染。
希望本文能够帮助你理解和应用 React.memo
,优化你的 React 应用程序的性能!
转载自:https://juejin.cn/post/7239528592883056698