useMemo与useCallback

本文介绍了React Hooks中的useCallback和useMemo,它们都是用于优化性能的工具。useCallback用于固定函数引用,避免不必要的子组件重新渲染,而useMemo则用于缓存计算结果,减少重复计算。通过示例解释了如何在实际场景中使用这两个Hooks进行性能优化,例如在处理复杂计算和防止组件不必要的渲染。同时,文章对比了两者的区别,指出它们在缓存数据和提升应用效率上的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.useCallback

用于得到一个固定引用值的函数,通常用它进行性能优化

useCallback:
该函数有两个参数:

  1. 函数,useCallback会固定该函数的引用,只要依赖项没有发生变化,则始终返回之前的函数地址
  2. 数组,记录依赖项
    该函数的返回值:引用相对固定的函数地址

例1:

		//伪代码
       function TEXT(props) {
            console.log('text render')
            return (
                <div>
                    {props.text}
                    <Button onClick={props.onClick} />
                </div>
            )
        }

        function Parent() {
            const [txt, setTxt] = useState(123)
            const [n, setN] = useState(0)
            const handleClick = useCallback(() => {
                set(txt + 1)
            }, [txt])
            const handleClick=()=>{
                 set(txt + 1)
             }
            // 注释1: const handleClick = useCallback(() => {
            //    set(txt + 1)
            //  }, [txt])

           //注释2: const handleClick=useMemo(()=>{
          //              return ()=>{
          //                  setText(txt+1)
           //              }
           //          },[txt])
            return (
                <div>
                    <Text text={txt} onClick={handleClick} />
                    <input type='number' value={n} onChange={() => {
                        setN(parseInt(e.target.value))
                    }} />
                </div>
            )
        }

parent组件中引用了TEXT组件,父组件input 变化会触发父组件重新渲染;每次父组件重新渲染,都会使TEXT组件也重新渲染。

而使TEXT组件重新渲染的原因是,传入的props改变了,其中,text并没有变,而是每次Parent重新渲染时,都会重新创建一个handleClick函数,函数内容没有变,函数的地址变了,所以TEXT会重新渲染

解决方法:父组件触发input时,不要改变handleClick的地址就好了。useCallback正好有这个功能,如下注释1的代码:当依赖项没有改变时,则useCallback始终返回之前的函数地址。它返回一个函数,赋值给handleClick。对于TEXT组件来说,props的text没有变,传入函数(地址)也没有变。所以不会重新渲染

2.useMemo

用于保存一些比较稳定的数据,通常用于性能优化

如上例子如果用useMemo实现,见注释2。

useCallback返回的是函数,useMemo返回的是函数的执行结果,即上面代码中return 里面的内容,可以是函数、数组、对象。

例2:

父组件App,子组件Item,父组件中,有一个复杂计算,循环10000次,初始时会执行一次,后面每次input改变都会执行。
优化,使用如下注释代码,useMemo返回值为一个数组,只要range不变,则这个复杂的计算不需要重新执行,子组件也不需要重新渲染

        function Item(props) {
            <li>{props.value} </li>
        }

        function App() {
            const [range,] = useState({ min: 1, max: 10000 })
            const [n, setN] = useState(0)

            const list = []
            for (let i = range.min; i < range.max; i++) {
                list.push(<Item key={i} value={i} />)
            }

            // const list = useMemo(() => {
            //     const list = []
            //     for (let i = range.min; i < range.max; i++) {
            //         list.push(<Item key={i} value={i} />)
            //     }
            //     return list
            // }, [range.max,range.min])
            return (
                <div>
                    <ul>
                        {llist}
                    </ul>
                    <input type='number' value={n} onChange={e => {
                        setN(parseInt(e.target.value))
                    }} />
                </div>
            )
        }

3.对比

共同点:
两者都用于缓存数据,性能优化;接收参数是一样的,第一个参数为回调函数,第二个表示以来的数据

区别:
useMemo :缓存的结果是回调函数中return的值,主要用于缓存计算结果的值,应用场景如需计算的状态。

useCallback:缓存的结果是函数,主要用于缓存函数。因为函数式组件每次任何一个state发生变化,会触发整个组件更新,一些函数是没有必要更新的,此时就应该缓存起来,提高性能,减少对资源的浪费

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值