React hooks useCallback 指北

react useCallback 指北

基本使用

useCallback(callback: T, deps: DependencyList): callbackjavascript

把内联回调函数及依赖项数组做为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给通过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将很是有用。java

问题

useCallback 返回的函数里面缓存了什么数据react

import React, { useCallback, useState } from 'react';

class Child extends React.Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.flag !== this.props.flag;
  }

  render() {
    console.log('Child render');
    return <div>Child Count: {this.props.count}</div>;
  }
}

const UseCallBack = () => {
  const [count, setCount] = useState(0);
  const [selfCount, setSelfCount] = useState(100);

  const memoizedCallback = useCallback(() => {
    console.log('count change', count, selfCount);
  }, [count]);

  return (
    <div> <Child count={count} flag={memoizedCallback} /> <p>self Count:{selfCount}</p> <p onClick={() => setCount(count + 1)}>child count add</p> <p onClick={() => setSelfCount(selfCount + 1)}>self count add</p> <p onClick={() => memoizedCallback()}>callback click</p> </div> 复制代码

能够看到,当咱们改变 selfCount 的时候,因为咱们的deps里面只监听了 count,因此返回的 memoizedCallback 是没有变化的,Child 没有 re-render,当memoizedCallback执行的时候打印的selfCount 仍是以前的状态,没有发生变化。数组

结论

useCallback执行返回的函数,是第一个传入的第一个函数的 memoized 版本,而且会缓存 useState 的全部值,只有在 deps 发生变化,返回值才函数才会更新,其内部的 useState的 值才会更新 。缓存

使用场景

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = () => {
    setCount(c + 1);
  };

  return (
    <div> {count} <Child onClick={handleIncr} /> </div> ); } 复制代码

假设Child是一个很是复杂的组件,每一次点击它,咱们会递增count,从而触发组将从新渲染。由于Counter每次渲染都会从新生成handleIncr,因此也会致使Child从新渲染,无论Child使用了PureComponent仍是使用React.memo包装。bash

在这里我使用useCallback去缓存咱们的 handleIncr闭包

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div> {count} <Child onClick={handleIncr} /> </div> ); } 复制代码

只有在count发生变化的时候才会从新生成 handleIncr,这样虽然能避免了一些性能问题,可是若是须要监听的变量过多,好比 useCallback(fn, [a, b,c, d]) 这样就会让代码变的很乱。 其实在这里咱们只要改变一下思路,在setCount 这样操做的时候,不用闭包中的变量,而是使用函数,获取最新的值。函数

const Child = React.memo(({ onClick }) => {
  console.log('child render');
  return <div onClick={onClick}>click</div>;
});

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      {count} <Child onClick={handleIncr} />
    </div>
  );
}
复制代码

这样 handleIncr 在每次 Counter re-render 的时候都不会改变,而且每次操做的也是最新值性能

相关文章
相关标签/搜索