React-useEffectuseCallbackuseMemo的个人理解

9次阅读

共计 1588 个字符,预计需要花费 4 分钟才能阅读完成。

本文记录个人对 React 的 hook 中 useEffect,useCallback,useMemo 的个人理解。
三者的定义:

useEffect(didUpdate, deps);

const memoizedCallback = useCallback(() => {doSomething(params);
  }, deps);

const memoizedValue = useMemo(() => computeExpensiveValue(params), deps);

三者的第二个 deps 是一个数组,表示依赖的参数列表,当依赖列表中任一参数变化时,则重新执行前面的函数。如 deps = [a,b], 表示 a 或者 b 发生变化则执行前面的函数(注意对象和值的变化方式不同)。
deps=[]时,表示只会在组件第一次渲染成功之后执行一次。

useEffect

didUpdate 是一个包含命令式、且可能有副作用代码的函数。
didUpdate 是组件渲染成功且 deps 依赖参数发生变化时执行的函数,也就是说 useEffect 会执行 didUpdate
didUpdate 可以没有返回值,只是执行 didUpdate 的内容。
didUpdate 当它有返回值时,返回值必须是个可执行的函数,目的是用于清除 didUpdate 执行过程中产生的订阅或者计时器等资源。同时如果 didUpdate 多次触发,则在每次重新执行前都会先执行返回的可执行函数。(官方称之为清除 effect)
如下:

useEffect(() => {const timer = setInterval(()=>{console.log('effect')
  }, 10*1000);
  return () => {
    // 清除定时器
    clearInterval(timer);
  };
});

因此对于 useEffect 来说,didUpdate 时 deps 有变化时就是执行的,didUpdate 若有返回值时,则在下次执行 didUpdate 时会先执行其返回的函数。

useCallback

返回一个 memoized 回调函数,我的理解即返回一个函数的句柄,等同于函数的变量,因此你可以使用 memoizedCallback()进行执行该函数或者传递给事件和子组件,这里可以推荐绝大多数事件或者子组件的方法使用 useCallback,避免组件更新重复渲染。
因此 useCallback 中的 doSomething 并不会在定义时就执行,而是需要手动调用返回的 memoizedCallback 才是真的执行。简单理解为 useCallback 定义了一个函数,仅在 deps 发生变化时重新定义该函数,否则该函数的变量不会变化,事件和子组件内容也就不用重新绑定或者渲染。

useMemo

返回一个 memoized 值,useMemo 函数每当 deps 发生变化时都会调用执行 computeExpensiveValue 的内容,这是与 useCallback 最大的不同,useCallback 不执行 doSomething 的内容,只是重新刷新函数句柄。
因此在官方上有这样的一个等式:
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
这应该看懂了吧。deps 发生变化时,useCallback 返回的是一个可执行 fn 的句柄,而 useMemo 则是执行 ()=>fn,但是因为返回的是 fn 函数,因此当调用这两种时其实执行的是相同的fn 函数内容。

总结

我自身对三者的理解是基于 hook 定义时:首参是否执行和各自返回内容的作用与差异进行理解,如果本文无法准确描述清楚,建议你也可以从这两方面进行入手分析三者之间的区别和用途。
当然这样的解释和理解可能无法去解释什么情况用 useEffect、useCallback、useMemo。但是作为开发者而言,理解 hook 其定义的差异,亦可理解其不同的用途目的,也就能区分清楚三者各自应在什么情况下进行使用。

正文完
 0