一、useMemo是什么
useMemo
是一个有记忆的钩子函数。它会记住函数返回的值。useMemo
接受一个回调函数和一个依赖项(就好比useEffects),并返回一个记住的值。只有当传递的任何依赖项的值发生变化时,它才会导致组件重新呈现。
const complexFunction = useMemo(() => {
...
},[replyValue]);
什么时候使用useMemo
只在函数运行非常昂贵的计算时才使用这个hooks
。
usememo如何工作的示例
在页面上新增了两个button
。
firstbutton
通过addNum
函数不断乘自身,并显示值在左侧。
secondbutton
不断累加1,并显示值在左侧。
import React, { useState } from 'react';
import { render } from 'react-dom';
const Parent = () => {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
console.log('父组件触发');
const addNum = (n) => {
//无论是count变化还是count2变化都重新触发了该方法
console.log('first触发');
return n * n;
};
const value = addNum(count);
return (
<main>
<p>
FirstCount: {value}{' '}
<button onClick={() => setCount((count) => count + 1)}>first*first</button>{' '}
</p>
<p>
SecondCount: {count2}{' '}
<button onClick={() => setCount2((count2) => count2 + 1)}>
second +1
</button>
</p>
</main>
);
};
render(<Parent />, document.getElementById('root'));
问题:点击second+1的button也会触发addNum进行重新计算,如果addNum一旦是很复杂的计算函数,则可能导致性能问题。
使用useMemo优化性能
import React, { useState,useMemo } from 'react';
import { render } from 'react-dom';
const Parent = () => {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
console.log('父组件触发');
const addNum = (n) => {
//只有是count变化才会触发该方法
console.log('first触发');
return n * n;
};
// const value = addNum(count);
const value = useMemo(() => addNum(count), [count]);
return (
<main>
<p>
FirstCount: {value}{' '}
<button onClick={() => setCount((count) => count + 1)}>first*first</button>{' '}
</p>
<p>
SecondCount: {count2}{' '}
<button onClick={() => setCount2((count2) => count2 + 1)}>
second +1
</button>
</p>
</main>
);
};
render(<Parent />, document.getElementById('root'));
二、memo是什么
memo
和useMemo
都是是一个有记忆的钩子函数。useMemo
它会记住函数返回的值。而memo
它是作用于组件上,同样接受一个回调函数和一个依赖项(这个依赖项是接受true
或者false
)。只有当传递的任何依赖项的值发生变化时,它才会导致组件重新呈现。
Memo如何工作的示例
在上文代码基础上,加入了一个<Child />
,并且把count2的值传递给<Child count2 ={count2} />
import React, { useState, useMemo } from 'react';
import { render } from 'react-dom';
const Parent = () => {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
console.log('父组件触发');
const addNum = (n) => {
console.log('first触发');
return n * n;
};
const value = useMemo(() => addNum(count), [count]);
return (
<main>
<p>
FirstCount: {value}{' '}
<button onClick={() => setCount((count) => count + 1)}>first*first</button>{' '}
</p>
<p>
SecondCount: {count2}{' '}
<button onClick={() => setCount2((count2) => count2 + 1)}>
second +1
</button>
</p>
<Child count2={count2}/>
</main>
);
};
const Child = ({count2}) => {
//无论是更新count1还是count2子组件都会重新渲染
console.log("子组件重新渲染")
return (
<div>
<p>孩子组件:{count2}</p>
</div>
);
};
render(<Parent />, document.getElementById('root'));
问题:点击frist*first
按钮时也会触发<Child />
的重新渲染,如果<Child />
Dom比较复杂,每次频繁渲染则可能导致性能问题。
使用Memo优化性能。只在secondCount
变化才会触发<Child />
组件重新渲染。
import React, { useState, useMemo,memo } from 'react';
import { render } from 'react-dom';
const Parent = () => {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
console.log('父组件触发');
const addNum = (n) => {
console.log('first触发');
return n * n;
};
const value = useMemo(() => addNum(count), [count]);
return (
<main>
<p>
FirstCount: {value}{' '}
<button onClick={() => setCount((count) => count + 1)}>first*first</button>{' '}
</p>
<p>
SecondCount: {count2}{' '}
<button onClick={() => setCount2((count2) => count2 + 1)}>
second +1
</button>
</p>
<Child count2={count2}/>
</main>
);
}
const isEqual = (pre,cur)=>{
if(pre.count2!==cur.count2){
//更新Child
return false
}
//不更新Child
return true
}
const Child = memo((props) => {
//只有count2改变才会触发更新
console.log("子组件重新渲染")
return (
<div>
<p>孩子组件:{props.count2}</p>
</div>
);
},isEqual);
render(<Parent />, document.getElementById('root'));
注意事项
UseMemo
或者memo
都是使用了一些复杂的逻辑,所以过度使用它可能会对组件造成弊大于利。此外,在react文档中指出,react
有时可能会选择忘记一些以前记住的值,并在下一次渲染时重新计算它们,这样即使没有UseMemo
或者memo
,您的组件可能比使用这两个钩子时运行得更快。