简介
在了解useMemo之前,要先了解什么是虚拟dom.在react类组件里的render每次被触发的时候都做了什么事情?
1.更新虚拟dom
2.更新后,新的虚拟dom和旧的虚拟dom如果有差异,则更新的真实的dom,否则则不更新真实的dom
什么是useMemo
官方的说法是:做性能优化用的,如果说类组件的性能优化的方法是shouldComponentUpdate 和 PureComponent,那么给函数组件做性能优化的就是使用useMemo.
简单来讲:在前端开发过程中,我们需要缓存一些内容,避免在渲染过程中因大量不必要的好事计算而导致的性能问题。为此React提供了一些方法可以帮助我们去实现数据的缓存,useMemo就是其中之一。
特性
useMemo类似于vue的计算属性,监听某个值的变化,根据变化的值从新计算新值;
useMemo会缓存结果,如果监听的值每月发生变化,即使组件重新渲染,也不会重新发生计算,这个行为有助于避免在每个渲染上进行昂贵的计算;
使用方式/语法
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
举一个栗子
Parent.js
import React, { useState } from 'react';
import Son from './Son'
export default (props)=>{
const [number,setNumber]=useState(0)
const [name, setName]=useState('Yui')
return(
<>
<button onClick={()=>{setNumber(number+1)}}>{'number is:'+number}</button>
<button onClick={()=>{setName('rena')}}>{'change name'}</button>
<Son name={name}/>
</>
)
}
这个组件里面只有两个 state,一个 name,一个 number,把 number 作为 props 传入了子组件。有两个按钮,分别改变 number 和 name 的值。
son.js
import React, { Component, useMemo } from "react";
export default (props) => {
const showName = (name) => {
console.log("Son render",2);
return "my name is " + name;
};
return (
<>
<div>
{useMemo(() => {
console.log("memo",1);
showName(props.name);
}, [props.name])}
</div>
<div>{showName(props.name)}</div>
</>
);
};
过程:
showName这个函数出现在了渲染函数中,那么它是useMemo的一个合适的输入;
注意:父组件只是往子组件传入的name,但是当点击改变number的按钮时,第二个showName仍然会被执行,但是name的值并没有实质性的改变,虚拟dom却被替换了,这意味着,这次更改虚拟dom是完全每月意义的,浪费的。
第一个shouName由于放在useMemo里面,所以并没有被调用,请注意第二个参数。prop.name.它的意思是,只要name发生变化的时候,useMomo传入的回调函数才会被调用。这是为了避免重复渲染,也就是,避免了更改虚拟dom,继而操作真实dom.
也就是说:假如我们单击 change name 按钮,两个showName函数都会被执行。
再举一个栗子
import { useMemo, useState, memo } from "react";
interface IProps {
value: number
}
let Con = memo((props:IProps) => {
console.log("render Con")
return (<div>{props.value}</div>)
})
export default function Home() {
const [count, setCount] = useState(0);
const [value, setValue] = useState(0);
const cachedValue = useMemo(function() {
return count + 1
}, [count])
return (
<>
<div>
{count}
</div>
<div>
{value}
</div>
<Con value={cachedValue} />
<button onClick={() => setCount(v => v + 1)}>Add Count</button>
<button onClick={() => setValue(v => v + 1)}>Add Value</button>
</>
);
}
useMemo 接收2个参数,第一个参数接收一个 factory 函数 ,函数的返回值即是 useMemo的返回值,第二参数是依赖列表,如果依赖列表中的值发生变化,就会引发组件的重渲染,并重新执行函数拿到新的值。
在上面的例子中 cachedValue 变量的求值依赖于count,如果 count 的不发生变化, useMemo 的 factory 便不会重新执行,cachedValue 的值也不会发生变化。
useMemo 作为一种性能优化的手段,可用于一些较为耗时耗资源的计算值的缓存, 避免因为这些计算影响渲染的效率。