react的一些性能优化
简介: 暂无~
父组件渲染导致子组件渲染
无优化
import { memo, useState } from 'react';
const ChildCpt = () => {
console.log('ChildCpt重新渲染了');
return <div>ChildCpt</div>;
};
const FatherCpt = () => {
const [count, setCount] = useState(1);
console.log('FatherCpt重新渲染了');
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 1)}>setCount</button>
<ChildCpt></ChildCpt>
</div>
);
};
export default memo(FatherCpt);
在没有任何优化的情况下,我们每点击一次setCount按钮,都会触发FatherCpt组件渲染,同时带动子组件ChildCpt也跟着渲染,在这个案例里面,很明显子组件是一个很纯的组件,即它没有依赖任何东西,其实它压根就没必要渲染,但是因为父组件渲染了,它也被迫进行了渲染,那么我们接下来就优化一下让ChildCpt,让它不渲染
请别钻牛角尖,说这个场景为什么不把ChildCpt给直接写到FatherCpt里,这只是一个极简的例子,事实上只要是组件就会有渲染问题,和组件本身的大小无关
React.memo优化
最简单的优化就是memo了:
import { memo, useState } from 'react';
const ChildCpt = memo(() => {
console.log('ChildCpt重新渲染了');
return <div>ChildCpt</div>;
});
const FatherCpt = () => {
const [count, setCount] = useState(1);
console.log('FatherCpt重新渲染了');
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 1)}>setCount</button>
<ChildCpt></ChildCpt>
</div>
);
};
export default memo(FatherCpt);
给ChildCpt组件包一层memo后,再次点击setCount按钮,就不会触发ChildCpt组件重新渲染了
缺点:如果用了react的eslint配置,可能 react/display-name 规则会报错,它要求memo里的函数需要有一个函数名,我们可以直接将memo里的箭头函数改成function ChildCpt()就好了,但是看上去就怪怪的,或者我们可以单独的将ChildCpt抽离出去,然后通过import引入进来,这样可能好看点
useMemo
import { memo, useMemo, useState } from 'react';
const ChildCpt = () => {
console.log('ChildCpt重新渲染了');
return <div>ChildCpt</div>;
};
const FatherCpt = () => {
const [count, setCount] = useState(1);
console.log('FatherCpt重新渲染了');
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 1)}>setCount</button>
{useMemo(
() => (
<ChildCpt></ChildCpt>
),
[]
)}
</div>
);
};
export default memo(FatherCpt);
因为ChildCpt不依赖任何数据,因此useMemo的依赖数组就是空数组,这样点击setCount,也不会触发ChildCpt组件重新渲染了
传参导致
无优化
import { memo, useState } from 'react';
const ChildCpt = memo(() => {
console.log('ChildCpt重新渲染了');
return <div>ChildCpt</div>;
});
const FatherCpt = () => {
const [count, setCount] = useState(1);
console.log('FatherCpt重新渲染了');
const sayhi = () => console.log('hi');
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 1)}>setCount</button>
<ChildCpt callback={sayhi}></ChildCpt>
</div>
);
};
export default memo(FatherCpt);
每次点击setCount按钮,都会触发ChildCpt重新渲染
传给ChildCpt组件的callback参数,或许ChildCpt会根据它做一些操作,但是,这里是不需要关心的,因为只要父组件FatherCpt重新渲染了,就一定会带动子组件渲染,而且父组件重新渲染的时候,会重新定义一个新的sayhi函数,因此,就会传给callback的sayhi就会被认为是一个新的函数,就会导致ChildCpt重新渲染
useCallback
import { memo, useCallback, useState } from 'react';
const ChildCpt = memo(() => {
console.log('ChildCpt重新渲染了');
return <div>ChildCpt</div>;
});
const FatherCpt = () => {
const [count, setCount] = useState(1);
console.log('FatherCpt重新渲染了');
const sayhi = useCallback(() => console.log('hi'), []);
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 1)}>setCount</button>
<ChildCpt callback={sayhi}></ChildCpt>
</div>
);
};
export default memo(FatherCpt);
使用useCallback并且设置了依赖数组为空数组后,再次点击setCount按钮,FatherCpt重新渲染了,但是不会导致ChildCpt重新渲染
最后更新于:2022-10-31 18:06:06