明白useCallback和react.memo对性能优化的影响

根据官网Hooks FAQ给出相关结论:
在这里插入图片描述
可以看出,除去极少数特殊情况,都不应该使用 useCallback。在一般情况下对性能上的影响可以忽略不计

那么,useCallback和react.memo具体有哪些用途?

//父组件
export default function () {
  let [a, setA] = useState(1)
  let [b, setB] = useState(1)

  const addA = () => {setA(++a)}

  const addB = () => {setB(++b)}
  
  return (
    <Fragment>
      <div>
        <button onClick={addA}>setA</button>
      </div>
      <div>
        <button onClick={addB}>setB</button>
      </div>
      <div>a:{a}</div>
      <div>b:{b}</div>
      <Child a={a}></Child>
    </Fragment>
  );
}
//子组件
const Child = (props: any) => {
  useEffect(() => {
    console.log("useEffect");
  }, [])

  let [c, setC] = useState(1)
  const add = () => {
    setC(++c)
  }
  
  return (
    <Fragment>
      {console.log("render")}
      <div style={{ height: "20px" }}></div>
      <div style={{ border: "1px solid #ddd" }}>
        <div>子组件</div>
        <div>
          <button onClick={add}>add</button>
        </div>
        <div>c:{c}</div>
      </div>
    </Fragment>
  );
}

功能上是父组件有两个按钮,其中一个按钮的值会传递给子组件。
现在,当点击setA和setB按钮的时候,都会导致子组件调用render函数,控制台会输出"render"。
但是,由于setA点击会传递参数a给到子组件,子组件会重新渲染。而setB没有值传递给子组件,所以子组件不需要重新渲染,这里就造成了子组件的重新渲染影响了性能。

所以,在这里引入了react.memo。
在父组件不变的情况下。子组件使用memo进行包裹。

const Child = memo((props: any) => {

  useEffect(() => {
    console.log("useEffect");
  }, [])

  let [c, setC] = useState(1)

  const add = () => {
    setC(++c)
  }

  return (
    <Fragment>
      {console.log("render")}
      <div style={{ height: "20px" }}></div>
      <div style={{ border: "1px solid #ddd" }}>
        <div>子组件</div>
        <div>
          <button onClick={add}>add</button>
        </div>
        <div>c:{c}</div>
      </div>
    </Fragment>
  );
})

这时候就会当点击setA的时候,子组件重新渲染。而点击setB的时候,子组件不重新渲染。

现在,有另外一种情况。父组件增加一个methods方法传递给到子组件。useCallback主要包裹父组件传递给子组件的函数。

export default function () {
  let [a, setA] = useState(1)
  let [b, setB] = useState(1)

  const addA = () => {setA(++a)}

  const addB = () => {setB(++b)}

  const methods = useCallback(() => {
    console.log(123);
  }, [])

  return (
    <Fragment>
      <div><button onClick={addA}>setA</button></div>
      <div><button onClick={addB}>setB</button></div>
      <div>a:{a}</div>
      <div>b:{b}</div>
      <Child a={a} methods={methods}></Child>
    </Fragment>
  );
}

这时候memo就不生效了。不管点击setA或setB。都会导致子组件重新渲染。控制台都会输出"render"。
这时候就要用上useCallback了

export default function () {
  let [a, setA] = useState(1)
  let [b, setB] = useState(1)

  const addA = () => {setA(++a)}

  const addB = () => {setB(++b)}

  const methods = useCallback(() => {
    console.log(123);
  }, [])

  return (
    <Fragment>
      <div><button onClick={addA}>setA</button></div>
      <div><button onClick={addB}>setB</button></div>
      <div>a:{a}</div>
      <div>b:{b}</div>
      <Child a={a} methods={methods}></Child>
    </Fragment>
  );
}

使用useCallback将传递给子组件的methods方法包裹。这时候点击setA会重新渲染子组件(因为有props传递给子组件),而setB不会重新渲染子组件了。

总结:useCallback一般是和react.memo一起使用的。但是,根据闭包的理解,useCallback传递的是一个闭包函数,所以存在一定的风险。除非是计算量特别大的子组件这种极端情况,否则不推荐使用。

欢迎大家指正,互相学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蛋蛋的老公

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值