useCallback和useMemo的正确用法详解

 更新时间:2023年01月15日 10:43:48   作者:糖瓶  
这篇文章主要为大家介绍了useCallback和useMemo的正确用法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

现实很多项目存在大量的useMemo和useCallback,大多数的使用并没有起到实际作用,使得项目的渲染效率更低了。

我们在应用程序中使用useMemo和useCallback这两个Hook,主要是因为想要缓存结果:

  • 缓存props值,防止重复渲染。
  • 缓存复杂的计算,避免重复计算。

所以我们经常这样使用这两个Hook:

缓存值

useMemo 缓存value,防止重新渲染。以下是伪代码:

const AppItem = ({item, data}) => <button>{item.val + newDate}</button>
const App = ({data}) => {
  const newDate = useMemo(() => data.value, [data.value])
  return (
    <>
      {
        list.map(item => {
          return <AppItem key={item.id} item={item} data={newDate} />
        })
      }
    </>
  )
}

缓存函数

useCallback缓存click 事件,防止重复渲染。以下是伪代码:

const AppItem = ({item, data, onClick}) => <button onClick={onClick}>{item.val + newDate}</button>
const App = ({data}) => {
  const newDate = useMemo(() => data.value, [data.value])
  const onClick = useCallback(() => {
    // ...
  }, [])
  return (
    <>
      {
        list.map(item => {
          return <AppItem key={item.id} item={item} data={newDate} onClick={onClick} />
        })
      }
    </>
  )
}

上述是我们经常见到的场景。但是这样使用就一定是正确的吗?答案是否定的。之前写过一篇React为什么会重新渲染的文章。这里在解释下。

组件为什么会重新渲染

重新渲染其中一个原因就是:state 或者 props 发生变化时。所以我们很天真的认为只要state或者props不变,组件就不会重新渲染了。

组件的重新渲染还有一个原因,我们知道但是经常在我们写代码的时候会忽略的原因:就是他的父组件重新渲染了。父组件渲染了,我们只在子组件内部缓存值或者函数是没有作用的。

看一个例子:

const App = () => {
	const [count, setCount] = useState(0)
  return (
    <>
      <button onClick={() => setCount(count+1)}>点我</button>
      <OtherComp />
    </>
  )
}

我们可以看到:点击按钮,App组件重新渲染,他的子组件OtherComp虽然没有任何的state或者props变化,但是他也重新渲染了。如果这个子组件也有子组件,以此类推,就会形成一条渲染链。

但是我们不是经常这样写吗:在这个组件中使用缓存手段。

const App = ({val}) => {
	const [count, setCount] = useState(0)
  const onClick = useCallback(() => {
    // ...
  }, [])
  const data = useMemo(() => val, [val])
  return (
    <>
      <button onClick={() => setCount(count+1)}>点我</button>
      <OtherComp onClick={onClick} data={data} />
    </>
  )
}

这样并不会阻止子组件的重新渲染。怎样解决呢?当然是还要缓存子组件了。

const OtherCompMemo = React.memo(OtherComp)
const App = ({val}) => {
	const [count, setCount] = useState(0)
  const onClick = useCallback(() => {
    // ...
  }, [])
  const data = useMemo(() => val, [val])
  return (
    <>
      <button onClick={() => setCount(count+1)}>点我</button>
      <OtherCompMemo onClick={onClick} data={data} />
    </>
  )
}

现在React会识别props没有变化,onClick 和 data也被缓存了,所以需要配合使用。

缓存复杂的计算

根据React文档:useMemo是用来缓存复杂计算的。假设有一个100000项的数组需要排序操作,此时我们应该缓存复杂的计算:

const dataList = ({data}) => {
  const contentNode = useMemo(() => {
    return data.map(item => {
        return <div key={item}>{item}</div>
      })
  }, [data, sort]);
  return contentNode;
}

什么是复杂的计算

  • 你可以通过 preformance.now() 进行计算消耗的时间。
  • React官方的开发工具中的profiler 记录查看,记录里会显示复杂的计算。

何时进行优化呢

  • 如果你可以通过组织代码结构来提高性能,那就没有必要使用useCallback和useMemo。
  • 如果你不知道使用useCallback和useMemo能否带来更大的好处,就不需要使用它们,因为使用它们也需要消耗性能。

总结

  • useMemo和useCallback只是针对重新渲染才是有帮助的,对第一次的渲染是有害的,消耗性能的。
  • 大多数情况下,单独使用useMemo和useCallback或memo是没有帮助的,需要结合父组件具体情况来看。
  • 其实大多数情况下,我们并不需要这两个hook,使用它们只会影响初始化的渲染。

以上就是useCallback和useMemo的正确用法详解的详细内容,更多关于useCallback和useMemo用法的资料请关注脚本之家其它相关文章!

相关文章

  • React使用useImperativeHandle自定义暴露给父组件的示例详解

    React使用useImperativeHandle自定义暴露给父组件的示例详解

    useImperativeHandle 是 React 提供的一个自定义 Hook,用于在函数组件中显式地暴露给父组件特定实例的方法,本文将介绍 useImperativeHandle的基本用法、常见应用场景,需要的可以参考下
    2024-03-03
  • React和Vue中实现锚点定位功能

    React和Vue中实现锚点定位功能

    在React中,可以使用useState和useEffect钩子来实现锚点定位功能,在Vue中,可以使用指令来实现锚点定位功能,在React和Vue中实现锚点定位功能的方法略有不同,下面我将分别介绍,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • 详解React Native网络请求fetch简单封装

    详解React Native网络请求fetch简单封装

    本篇文章主要介绍了详解React Native网络请求fetch简单封装,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • React中的Context应用场景分析

    React中的Context应用场景分析

    这篇文章主要介绍了React中的Context应用场景分析,Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props,通过实例代码给大家介绍使用步骤,感兴趣的朋友跟随小编一起看看吧
    2021-06-06
  • 详解React Native开源时间日期选择器组件(react-native-datetime)

    详解React Native开源时间日期选择器组件(react-native-datetime)

    本篇文章主要介绍了详解React Native开源时间日期选择器组件(react-native-datetime),具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • React Native 中限制导入某些组件和模块的方法

    React Native 中限制导入某些组件和模块的方法

    这篇文章主要介绍了React Native 中限制导入某些组件和模块的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • React实现浮层组件的思路与方法详解

    React实现浮层组件的思路与方法详解

    React 浮层组件(也称为弹出组件或弹窗组件)通常是指在用户界面上浮动显示的组件,本文主要介绍了浮层组件的实现方法,感兴趣的小伙伴可以了解下
    2024-02-02
  • React Form组件的实现封装杂谈

    React Form组件的实现封装杂谈

    这篇文章主要介绍了React Form组件的实现封装杂谈,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • ReactDOM.render在react源码中执行原理

    ReactDOM.render在react源码中执行原理

    这篇文章主要为大家介绍了ReactDOM.render在react源码中执行原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • React 事件绑定的实现及区别

    React 事件绑定的实现及区别

    事件绑定也是其中一部分内容,通过事件委托和事件合成,React 在内部对事件进行优化和处理,减少了事件处理函数的调用次数,从而提升了性能,本文主要介绍了React事件绑定的实现及区别,感兴趣的可以了解一下
    2024-03-03

最新评论