前言
React的性能优化大都是交由用户自己来做的,主要体现在减少不必要的渲染,减少不必要的js计算,从而达到性能优化的目的
class组件
PureComponent
优点:使用方便; 缺点:仅做浅层比较,对于复杂数据结构无法正确识别shouldComponentUpdate
这个大家都知道,也是最常用的,前提是不可以用PureComponent
使用方式:(nextProps, nextState) => boolean
*不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能;现在React正逐步减少shouldComponentUpdate的重要性
function组件
- React.memo
可以这么理解,React.memo = PureComponent + shouldComponentUpdate;因为它也是做浅层对比,也和should一样有具体的手动控制方法
不过memo的原理是记忆缓存上一次的渲染结果,而should是直接跳过更新
使用方法:
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
}, (prevProps, nextProps) => boolean);
*注意后面的回调函数返回结果和should是相反的
- React.useMemo(Hooks)
React官方定义:const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
通俗易懂的解释下:该方法接收两个参数,第一个是一个函数,返回一个值,第二个是他的依赖项,只有当依赖项里的值发生变化了,前面那个函数才会重新计算,否则不会重新计算,套用上次缓存下来的值,避免无用的js计算。
特地去搭了个服务演示一下,下面是我的代码:
import React from "react";
function App() {
const [num, setNum] = React.useState(1);
const [str, setStr] = React.useState("yeah");
const value = () => {
console.log("重新计算了嗷");
return str + "~~";
};
// const memoValue = React.useMemo(value,[str])
console.log('1')
return (
<div>
<h1>在线调试页面</h1>
<span>{value()}</span>
<button onClick={() => setNum(num + 1)}>改变num</button>
<button onClick={() => setStr(str + '-')}>改变str</button>
</div>
);
}
export default App;
首先是没有用memo的情况,value的结果完全是跟着str走的,按理说我们想看到的是点击第一个按钮不触发重新计算,但是它计算了,因为React的机制,页面的state改变了,就会重新渲染,那么return里的代码会重新走一遍;
上图是我分别点击了两个按钮之后触发的console,接下来试试useMemo
import React from "react";
function App() {
const [num, setNum] = React.useState(1);
const [str, setStr] = React.useState("yeah");
const value = () => {
console.log("重新计算了嗷");
return str + "~~";
};
const memoValue = React.useMemo(value,[str])
console.log('1')
return (
<div>
<h1>在线调试页面</h1>
<span>{memoValue}</span>
<button onClick={() => setNum(num + 1)}>改变num</button>
<button onClick={() => setStr(str + '-')}>改变str</button>
</div>
);
}
export default App;
再次点击两个按钮:
显然,虽然页面重新渲染了,但是value没有重新计算了,是不是很神奇~
例子只是很简单的一个展示,当计算开销大的时候,比如有多次循环或者递归啥的,这性能优化可就明显了
- React.useCallback
和useMemo没什么差别,区别是返回的是一个回调函数,memo返回的是值const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
目前想到的就是这些,也是比较常用的,后续有其他的想法会继续更新~