useMemo和useCallback使用场景

这篇具有很好参考价值的文章主要介绍了useMemo和useCallback使用场景。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

useMemo和useCallback使用场景

useMemo到底是做什么的,工作原理是什么。

简而言之,useMemo是用来缓存计算属性的。
计算属性其实是函数的返回值,或者说指那些以返回一个值为目标的函数。
有些函数,需要我们手动的去点击,去完成一些动作才触发。而有些函数,则是直接在渲染的时候就执行,在DOM区域被当作属性值一样去使用。
后者,就被称为计算属性。
而计算属性,最后一定会使用return返回一个值!

useMemo在什么情况下使用

第一种情况

当我们的某一个计算属性真的需要大量的计算时候

//Com组件
const Com = () => {
    
    //这种就是完全没必要被useMemo缓存的,计算过程一共也就一个创建变量,一个加一,缓存它反而亏本
     const computedFun1 = () => {
        let number = 0;
        number = numebr +1;
        return number;
    }

    //这个就需要缓存一下了,毕竟他每次计算的计算量还是蛮大的。
    const computedFun2 = () => {
        let number =  0;
        for(let i=0;i<100000;++i){
            number = number +i-(number-i*1.1);
        }
        return number;
    }
    
    return <div onClick = {handleFun1}>
        computed1:{computedFun1()}  //这个计算量小,是不需要使用useMemo缓存的,缓存它反而亏本
        computed2:{computedFun2()} //这个计算量大,需要缓存。
    </div>
}

在上面的示例中。

computedFun1这个函数是完全没必要去缓存的。计算量太小了。我们使用useMemo成本都比它计算的成本高。

而computedFun2这个函数是需要去缓存的,毕竟这个函数都计算量属实有点大了。缓存起来,能不执行就不执行。

第二种情况

当子组件依赖父组件的某一个依赖计算属性并且子组件使用了React.memo进行优化了的时候。
我想,能看到这里的同学一定不需要我太详细的讲解什么是React.memo。

简单说,React.memo()是通过校验props中的数据是否改变的来决定组件是否需要重新渲染的一种缓存技术,具体点说React.memo()其实是通过校验Props中的数据的内存地址是否改变来决定组件是否重新渲染组件的一种技术。

假设我们往子组件传入一个计算属性,当父组件的其他State(与子组件无关的state)改变的时候。那么,因为状态的改变,父组件需要重新渲染,那被React.memo保护的子组件是否会被重新构建?

import {useMemo,memo} from 'react';
/**父组件**/
const Parent = () => {
    const [parentState,setParentState] = useState(0);  //父组件的state
    
    //需要传入子组件的函数
    const toChildComputed = () => {
        console.log("需要传入子组件的计算属性");
        return 1000;
    }
    
    return (<div>
          <Button onClick={() => setParentState(val => val+1)}>
              点击我改变父组件中与Child组件无关的state
          </Button>
          //将父组件的函数传入子组件
          <Child computedParams={toChildComputed()}></Child>
    <div>)
}

/**被memo保护的子组件**/
const Child = memo(() => {
    consolo.log("我被打印了就说明子组件重新构建了")
    return <div><div>
})

问:当我点击父组件中的Button改变父组件中的state。子组件会不会重新渲染。乍一看,改变的是parentState这个变量,和子组件半毛钱关系没有,子组件还被React.memo保护着,好像是不会被重新渲染。但这里的问题是,你要传个其他变量进去这也就走的通了。但是传入的是函数,不行,走不通。子组件会重新渲染。

React.memo检测的是props中数据的栈地址是否改变。而**父组件重新构建的时候,如果不缓存计算属性,那么计算属性将会被重新计算执行,并返回一个新的值(这意味这返回了一个新的存储地址),新的计算属性传入到子组件中被props检测到栈地址更新。也就引发了子组件的重新渲染。
所以,在上面的代码示例里面,子组件是要被重新渲染的。

那么如何才能让子组件不进行重新渲染呢?useMemo第二种使用方法来了。

useMemo会在发现依赖没有变化之后返回旧的计算属性值。

使用useMemo包一下需要传入子组件的那个计算属性。那样的话,父组件重新渲染,子组件中的函数就会因为被useMemo保护而返回旧的计算属性值,子组件就不会检测成地址变化,也就不会重选渲染。

还是上面的代码示例,我们进行以下优化。

import {useMemo,memo} from 'react';
/**父组件**/
const Parent = () => {
    const [parentState,setParentState] = useState(0);  //父组件的state
    
    //需要传入子组件的函数
    //只有这里和上一个示例不一样!!
    //只有这里和上一个示例不一样!!
    //只有这里和上一个示例不一样!!
    //只有这里和上一个示例不一样!!
    //只有这里和上一个示例不一样!!
    //只有这里和上一个示例不一样!!
    const toChildComputed = useMemo(() => {
       console.log("需要传入子组件的计算属性");
       return 1000;
    },[])
    
    return (<div>
          <Button onClick={() => setParentState(val => val+1)}>
              点击我改变父组件中与Child组件无关的state
          </Button>
          //将父组件的计算属性传入子组件
          <Child computedParams={toChildComputed}></Child>
    <div>)
}

/**被memo保护的子组件**/
const Child = memo(() => {
    consolo.log("我被打印了就说明子组件重新构建了")
    return <div><div>
})

这样,子组件就不会被重新渲染了。
代码示例一和代码示例二中的区别只有被传入的子组件的计算属性(toChildComputed函数)是否被useMemo保护。
我们只需要使用useMemo保护一下父组件中传入子组件的那个函数(toChildComputed函数)保证它不会在没有必要的情况下返回一个新的内存地址就好了。

useMemo是不是用的越多越好?

不是!!!

缓存,需要成本!
缓存并不是免费的,所有被useMemo保护的函数都会被加入useMemo的工作队列。

在组件进行渲染并且此组件内使用了useMemo之后,为了校验改组件内被useMemo保护的这个计算属性是否需要重新计算,它会先去useMemo的工作队列中找到这个函数,然后还需要去校验这个函数都依赖是否被更改。

这其中,寻找到需要校验的计算属性和进行校验这两个步骤都需要成本
当我们大量的使用useMemo之后,非但不能给项目带来性能上的优化,反而会为项目增加负担,我们将这种情况戏称为:反向优化。

总结:

useMemo是用来缓存计算属性的,它会在发现依赖未发生改变的情况下返回旧的计算属性值的地址。
useMemo绝不是用的越多越好,缓存这项技术本身也需要成本。
useMemo的使用场景之一是:只需要给拥有巨大计算量的计算属性缓存即可。
useMemo的另一个使用场景是:当有计算属性被传入子组件,并且子组件使用了react.memo进行了缓存的时候,为了避免子组件不必要的渲染时使用

useCallback
useCallback与useMemo差不多,前者用来返回函数,后者用来返回值。

useCallBack不是每个函数都需要使用?

//Com组件
const Com =  () => {
 
    //示例1包裹了useCallBack的函数
    const fun1 = useCallBack(() => {
        console.log('示例一函数');
        ...
    },[])
    
     //示例2没有包裹useCallBack的函数
    const fun2 = () => {
        console.log('示例二函数');
        ...
    }
    return <div></div>
}

大家看上方这种结构的组件,Com组件中包含了fun1和fun2两个函数。

是不是认为当Com组件重新渲染的时候,只有fun2(没有使用useCallBack的函数)函数会被重新构建,而fun1(使用了useCallBack的函数)函数不会被重新构建。

实际上,被useCallBack包裹了的函数也会被重新构建并当成useCallBack函数的实参传入。

useCallBack的本质工作不是在依赖不变的情况下阻止函数创建,而是在依赖不变的情况下不返回新的函数地址而返回旧的函数地址。不论是否使用useCallBack都无法阻止组件render时函数的重新创建!!

每一个被useCallBack的函数都将被加入useCallBack内部的管理队列。而当我们大量使用useCallBack的时候,管理队列中的函数会非常之多,任何一个使用了useCallBack的组件重新渲染的时候都需要去便利useCallBack内部所有被管理的函数找到需要校验依赖是否改变的函数并进行校验。

在以上这个过程中,寻找指定函数需要性能,校验也需要性能。所以,滥用useCallBack不但不能阻止函数重新构建还会增加“寻找指定函数和校验依赖是否改变”这两个功能,为项目增添不必要的负担。文章来源地址https://www.toymoban.com/news/detail-617167.html

到了这里,关于useMemo和useCallback使用场景的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • react useState useEffect useMemo实际业务场景中的使用

    下面的代码实现了上面图片的功能

    2024年02月16日
    浏览(42)
  • React useMemo 实际开发使用小结

    useMemo 的原理是基于 memoization 技术。当你使用 useMemo 时,它会在组件渲染过程中缓存函数的计算结果,并在下一次渲染时,仅在依赖项(dependencies)发生变化时重新计算。如果依赖项没有发生变化,则直接返回之前缓存的结果,避免不必要的重复计算。 在组件初次渲染时,

    2024年02月16日
    浏览(40)
  • React中useMemo的简单使用

    useMemo主要用来解决使用React hooks产生的无用渲染的性能问题,用来做缓存用。 useMemo使用场景,比如有两个变量(依赖项),只需要在其中一个变量变化时发生变化,否则拿缓存的值;或者其中另一个变量的变化不需要引起重新计算时使用。该属性类似于vue中的计算属性,有

    2024年02月13日
    浏览(42)
  • React性能优化之Memo、useMemo

    React 的渲染机制,组件内部的 state 或者 props 一旦发生修改,整个组件树都会被重新渲染一次,即时子组件的参数没有被修改,甚至无状态组件 会造成性能浪费 React.memo 是 React 官方提供的一个高阶组件,用于缓存我们的需要优化的组件 React 中的组件被设计为在状态或 props 值

    2024年02月14日
    浏览(35)
  • React.Memo和useMemo的区别?

    hello world欢迎来到前端的新世界 😜当前文章系列专栏:react.js 🐱‍👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误,感谢大家指出)🌹 💖感谢大家支持!您的观看就是作者创作的动力 React.memo和useMemo是React中两个不同的特性,用

    2024年02月06日
    浏览(47)
  • React hooks之useEffect、useMemo优化技巧

    useEffect使用JSON.stringfy进行过滤,避免重复执行 将数组直接放入依赖数组可能不会按预期工作,因为数组比较是基于引用而不是内容。也就是说,如果数组引用没有变,即使数组内容发生了变化,副作用也不会重新运行。或者数组内饿哦那个没有改变但是引用却发生变化时,

    2024年02月12日
    浏览(46)
  • 【前端知识】React 基础巩固(四十四)——其他Hooks(useContext、useReducer、useCallback)

    在类组件开发时,我们通过 类名.contextType = MyContext 的方式,在类中获取context,多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context: 可以看到,当我们需要使用多个Context时,存在大量繁琐的嵌套代码;而Context Hook能够让我们通过Hook直接获取某个Context的值,如

    2024年02月14日
    浏览(46)
  • React 中的 useCallback 钩子函数

    useCallback 钩子函数有点像 useMemo 一样可以备份信息,而 useCallback 只是备份函数,除非某些参数发生变化,否则他不会重新运行其中的代码, 出现的问题:运行上述代码后,当我们在输入框中输入数字后,再去查看控制台的日志我们可以看到打印出了 params change 的信息,这就

    2024年02月09日
    浏览(40)
  • [React]useMemoizedFn和useCallback对比

    useMemoizedFn文档地址:https://ahooks.js.org/zh-CN/hooks/use-memoized-fn 在 React 中,自定义的 Hooks 内部的函数在以下常见的几种情况下会被重新赋值,导致更新引用: 组件重新渲染: 当组件重新渲染时,Hooks 内部的函数会被重新执行,从而导致函数的重新赋值和更新引用。 这意味着每

    2024年02月14日
    浏览(42)
  • React Hook之useCallback 性能优化

    上文 对比之前的组件优化说明React.memo的作用我们说了 React.memo的妙用 但是 它却并非万能 我们来看这个情况 我们子组件代码编写如下 这里 我们接收了父组件 props中的一个 dom1funt 函数 然后点击dom1funt按钮 触发这个dom1funt 然后 父组件代码编写如下 父组件 我们定义了这个传给

    2024年02月11日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包