Skip to content

React Hooks 系列 之 useCallback

介绍

useCallback 是 React Hooks 中的一个重要成员,它允许我们在多次渲染中缓存函数。简单来说,它可以帮助我们避免因为函数的重新创建而导致的不必要的重新渲染。

js
const cachedFn = useCallback(fn, dependencies);
const cachedFn = useCallback(fn, dependencies);

用法

1、跳过组件的重新渲染

当你优化渲染性能的时候,有时需要缓存传递给子组件的函数。例如,当你传递一个函数给一个被 memo 包裹的子组件时,useCallback 可以确保函数在多次渲染中保持不变,除非它的依赖发生改变。

demo 代码
jsx
import { useState, memo, useCallback } from "react";
import { Card, Button } from "antd";

function ChildComponent(props) {
  const { getText } = props;
  console.log("ChildComponent render");
  return <p>{getText()}</p>;
}

const MemoizedChildComponent = memo(ChildComponent);

function ParentComponent() {
  const [count, setCount] = useState(0);

  const getText = useCallback(() => {
    return "我是子组件,请在控制台查看打印结果!";
  }, [/* 依赖列表 */]);

  return (
    <Card title="案例 demo">
      <p>Current count: {count}</p>
      <Button onClick={() => setCount(count + 1)} type="primary">
        Increment
      </Button>
      <MemoizedChildComponent getText={getText} />
    </Card>
  );
}

export default ParentComponent;
import { useState, memo, useCallback } from "react";
import { Card, Button } from "antd";

function ChildComponent(props) {
  const { getText } = props;
  console.log("ChildComponent render");
  return <p>{getText()}</p>;
}

const MemoizedChildComponent = memo(ChildComponent);

function ParentComponent() {
  const [count, setCount] = useState(0);

  const getText = useCallback(() => {
    return "我是子组件,请在控制台查看打印结果!";
  }, [/* 依赖列表 */]);

  return (
    <Card title="案例 demo">
      <p>Current count: {count}</p>
      <Button onClick={() => setCount(count + 1)} type="primary">
        Increment
      </Button>
      <MemoizedChildComponent getText={getText} />
    </Card>
  );
}

export default ParentComponent;

在上面的案例中,只有当依赖列表中的值发生变化时,getText 函数才会被重新创建。

2、优化自定义 Hook

当你创建自定义Hook时,建议将返回的任何函数都包裹在useCallback中。这确保了Hook的使用者在需要时能够优化自己的代码。

demo 代码
jsx
import React, { useCallback } from "react";
import { Card, Button } from "antd";

function useCounter() {
  const [count, setCount] = React.useState(0);

  const increment = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return { count, increment };
}

function App() {
  const { count, increment } = useCounter();

  return (
    <Card title="案例 demo">
      <p>Count: {count}</p>
      <Button onClick={increment} type="primary">
        Increment
      </Button>
    </Card>
  );
}

export default App;
import React, { useCallback } from "react";
import { Card, Button } from "antd";

function useCounter() {
  const [count, setCount] = React.useState(0);

  const increment = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return { count, increment };
}

function App() {
  const { count, increment } = useCounter();

  return (
    <Card title="案例 demo">
      <p>Count: {count}</p>
      <Button onClick={increment} type="primary">
        Increment
      </Button>
    </Card>
  );
}

export default App;

调用 useCallback 后大致执行情况

null