我正在参加「掘金·启航计划」
前言
疑惑了很久,以为useMemo和useEffect 作用是一样的,因为书写形式和调用机制都十分的像,都是传入一个函数,都在关联变量发生变化时才去执行函数。其实这两者的区别十分的大,下面我将深入剖析这两者的不同,希望对大家有所帮助同时欢迎讨论指出问题!
const [countA, setCountA] = useState(1)
const [countB, setCountB] = useState(1)
function todo() {
console.log('todo触发')
return countA
}
return (
<div className="App">
<p>{todo()}</p>
<p>A:{countA}</p>
<p>B:{countB}</p>
<Button onClick={() => setCountA(countA + 1)}>点击A</Button>
<Button onClick={() => setCountB(countB + 1)}>点击B</Button>
</div>
)
分析需求: 在每次setState后,都会触发Dom重新渲染,会触发函数,但是现在我们只想让这个函数只在A改变的时候再触发,而不是每次重新渲染都触发。
此时是:点击A,点击B 都会触发todo函数
2.使用useEffect解决
此时我的第一反应就是使用useEffect来解决,将上面的函数用useEffect包裹,并设置依赖,只有name发生变化的时候才触发。
const [countA, setCountA] = useState(1)
const [countB, setCountB] = useState(1)
function todo(s?: any) {
console.log('todo触发' + s)
return countA
}
useEffect(() => {
console.log('countA')
todo('A')
}, [countA])
useEffect(() => {
console.log('countB')
}, [countB])
return (
<div className="App">
<p>A:{countA}</p>
<p>B:{countB}</p>
<Button onClick={() => setCountA(countA + 1)}>点击A</Button>
<Button onClick={() => setCountB(countB + 1)}>点击B</Button>
</div>
)
点击A打印结果是:
1. countA
2.todo触发A
从结果即可看出:useEffect是在Dom渲染之后,再执行函数。类似于componentDidMount,componentDidUpdate,componentWillUnmount三个函数的组合 但是这种方式有一个缺点,只是在渲染前控制,而如果有业务要求重新渲染控制需要在渲染期间控制,也就是在return中进行控制。useEffect是不能实现的。
2.使用useMemo解决
const [countA, setCountA] = useState(1)
const [countB, setCountB] = useState(1)
function todo(s?: any) {
console.log('todo触发' + s)
return countA
}
const memo = useMemo(() => {
console.log('memo 触发')
return () => countA
}, [countA])
return (
<div className="App">
<p>{memo()}</p>
<p>A:{countA}</p>
<p>B:{countB}</p>
<Button onClick={() => setCountA(countA + 1)}>点击A</Button>
<Button onClick={() => setCountB(countB + 1)}>点击B</Button>
</div>
)
点击A打印结果是:
1.memo 触发
2.todo触发
从结果即可看出:useMemo是在渲染期间执行函数,类比生命周期就是shouldComponentUpdate,因此useMemo就能解决一些问题,怎么在Dom改变的时候,控制某些函数不被触发。
1.假设在上面函数组件里面有一个定时任务,选用哪种方式来解决呢?是useEffect,还是useMemo呢?
function todo(s?: any) {
setInterval(() => {
console.log('触发了定时器')
}, 5000)
return countA
}
多次点击A打印结果是:
1.countA
2.todo触发了定时器A
可以发现 ‘todo触发了定时器A’ 在多次点击之后 输出的频率再增多。
原因是:每执行一次,又会添加一个定时器,这时就容易产生内存泄漏
3.总结
区别:1.useEffect会在组件渲染完毕后执行,和渲染无关的副作用。useMemo:会在在组件首次加载和重渲染期间执行,执行的函数需要和渲染相关的。 2.useEffect 没有返回值,useMemo有返回值 3.useMemo中不能做操作Dom之类的操作,这是属于 useEffect 的适用范畴
结束语
希望大家能够喜欢我的文章,我真的很用心在写,也希望通过文章认识更多志同道合的朋友。
最后伙伴们,如果喜欢我的可以给点一个小小的赞👍或者关注➕都是对我最大的支持。