hooks中useMemo和useCallback详解

要想学习useMemo必须要先知道React.memo,这两者都有一定的优化作用

memo的作用

当数据变化时,代码会重新执行一遍,但是子组件数据没有变化也会执行,这个时候可以使用memo将子组件封装起来,让子组件的数据只在发生改变时才会执行

案例

父组件点击countOne+1,子组件的入参countTwo不变,验证程序会不会执行子组件的代码

不使用memo的情况

只改变countOne的值时,虽然说countTwo的值没变,但是也执行了Child的打印语句

const UseMemo = () => {
  const [countOne, setOne] = useState(() => 0)
  const [countTwo, setTwo] = useState(() => 0)
  return (
    <div>
      <h1>{countOne}</h1>
      <button onClick={() => setOne((countOne) => countOne + 1)}>
        +countOne
      </button>
      <button onClick={() => setTwo((countTwo) => countTwo + 1)}>
        +countTwo
      </button>
      <Child count={countTwo}></Child>
    </div>
  )
}
 const Child = (props) => {
   console.log('child执行了')
   return <div>{props.count}</div>
 }

通过运行发现,Child里的代码执行了。

使用memo进行封装

将Child用memo封装一下,就可以使m不变就不执行Child,这个时候只要m的值不变,就不会执行Child组件

使用React.memo封装,会返回一个新的组件,调用新组件

const UseMemo = () => {
  const [countOne, setOne] = useState(() => 0)
  const [countTwo, setTwo] = useState(() => 0)
  return (
    <div>
      <h1>{countOne}</h1>
      <button onClick={() => setOne((countOne) => countOne + 1)}>
        +countOne
      </button>
      <button onClick={() => setTwo((countTwo) => countTwo + 1)}>
        +countTwo
      </button>
      <Child count={countTwo}></Child>
    </div>
  )
}
const Child = React.memo((props) => {
  console.log('child执行了')
  return (
    <div>
      {props.count}
    </div>
  )
})

这次执行就可以发现,改变了countOne,Child的代码并没有执行。

但是此时还有一个bug,如果在子组件Child上添加一个监听函数,无论修改countTwo的值与否,都会执行Child组件
const UseMemo = () => {
  const [countOne, setOne] = useState(() => 0)
  const [countTwo, setTwo] = useState(() => 0)
  const onClickChild = (props) => {
      console.log(props, 'aaaaaaa')
    setOne((countOne) => countOne + 1)
  }
  return (
    <div>
      <h1>{countOne}</h1>
      <button onClick={() => setOne((countOne) => countOne + 1)}>
        +countOne
      </button>
      <button onClick={() => setTwo((countTwo) => countTwo + 1)}>
        +countTwo
      </button>
      {/*但是如果传了一个引用,则React.memo无效。因为引用是不相等的*/}
      <Child count={countTwo} onClickChild={onClickChild}></Child>
    </div>
  )
}
const Child = React.memo((props) => {
  console.log('child执行了')
  return (
    <div
      onClick={() => {
        console.log('11')
        props.onClickChild('我给父组件传值啦!')
      }}
    >
      {props.count}
    </div>
  )
})

以上代码给Child传了个函数onClickChild,这就导致了即使countTwo没改变,Child也同样会被执行。

这是因为当点击countOne时,就会重新执行父组件代码,onClickChild空函数的地址会发生改变,所以说此时还是会执行Child的

这个时候就需要useMemo闪亮登场了

useMemo的作用

解决因函数更新而渲染自己的问题,就可以使用useMemo,使用它将函数重新封装

const onClickChild=useMemo(fn,array)监听变量,第一个参数是函数,第二个参数是依赖,只有依赖变化时才会重新计算函数

第一个参数是 () => value

第二个参数是依赖 [m, n]

const UseMemo = () => {
  const [countOne, setOne] = useState(() => 0)
  const [countTwo, setTwo] = useState(() => 0)
  const onClickChild = useMemo(() => {
    console.log('useMemo执行')
    return (props) => {
    console.log(props, 'aaaaaaa')
      setOne((countOne) => countOne + 1)
    }
  }, [countTwo])
  return (
    <div>
      <h1>{countOne}</h1>
      <button onClick={() => setOne((countOne) => countOne + 1)}>
        +countOne
      </button>
      <button onClick={() => setTwo((countTwo) => countTwo + 1)}>
        +countTwo
      </button>
      <Child count={countTwo} onClickChild={onClickChild}></Child>
    </div>
  )
}
const Child = React.memo((props) => {
  console.log('child执行了')
  return (
    <div
      onClick={() => {
        console.log('11')
        props.onClickChild('我给父组件传值啦!')
      }}
    >
      {props.count}
    </div>
  )
})

通过以上代码运行改变countOne,Child就不会执行啦

这里要注意下,useMemo是用来消除上面在子组件Child上添加函数,造成子组件重复渲染的问题,

通俗点说就是处理onClickChild这个函数带来的bug

如果Child不是用React.memo包裹的,那么改变countOne同样会触发Child改变。

所以通常二者是结合使用的。

注意:
  • 如果你的value是个函数,那么你就要写成useMemo(() => fn, deps)
  • 这是一个返回函数的函数,比较复杂;于是就有了useCallback,你可以使用useCallback
useCallback的作用

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

上面的onClickChild函数用useCallback写法如下:

const UseMemo = () => {
  const [countOne, setOne] = useState(() => 0)
  const [countTwo, setTwo] = useState(() => 0)
  const onClickChild = useCallback(
       (props) => {
         console.log(props, 'aaaaaaa')
         setOne((countOne) => countOne + 1)
       },
       [countTwo]
     )
  return (
    <div>
      <h1>{countOne}</h1>
      <button onClick={() => setOne((countOne) => countOne + 1)}>
        +countOne
      </button>
      <button onClick={() => setTwo((countTwo) => countTwo + 1)}>
        +countTwo
      </button>
      {/*但是如果传了一个引用,则React.memo无效。因为引用是不相等的*/}
      <Child count={countTwo} onClickChild={onClickChild}></Child>
    </div>
  )
}
const Child = React.memo((props) => {
  console.log('child执行了')
  return (
    <div
      onClick={() => {
        console.log('11')
        props.onClickChild('我给父组件传值啦!')
      }}
    >
      {props.count}
    </div>
  )
})

到这里React.memo,useMemo,useCallback就都解释完了,喜欢的小伙伴点个收藏哦。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值