ReactJS - 使用 useCallback:初学者指南

你好,未来的 React 开发者们!今天,我们将深入了解 React 的一个强大钩子:useCallback。如果你是编程新手,不用担心;我会一步步引导你理解这个概念,就像我多年来教导许多学生一样。让我们一起踏上这段激动人心的旅程!

ReactJS - Using useCallback

useCallback 是什么?

在我们深入了解之前,先来了解一下 useCallback 是怎么回事。想象你正在烤饼干(我喜欢这个类比,因为毕竟,谁不喜欢饼干呢?)你有一个每次都会使用的特殊配方。useCallback 就像写下这个配方一次,并在每次需要烤饼干时使用它,而不是每次都尝试记住它。

在 React 术语中,useCallback 是一个帮助我们通过记忆(memoization)函数来优化应用程序性能的钩子。

useCallback 钩子的签名

让我们看看如何编写 useCallback

const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);

别慌!我知道这看起来可能很复杂,但我们来分解一下:

  1. memoizedCallback:这是 useCallback 返回的函数。
  2. () => { doSomething(a, b); }:这是我们想要记忆的函数。
  3. [a, b]:这被称为依赖数组。它告诉 React 何时重新创建我们的函数。

可以这样理解:你正在告诉 React,“嘿,记住这个函数,只有当 ab 改变时才给我一个新的。”

应用 useCallback

现在,让我们通过一个简单示例来看看 useCallback 的实际应用:

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

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

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

return (
<div>
计数:{count}
<button onClick={increment}>增加</button>
</div>
);
}

让我们分解一下:

  1. 我们从 React 中导入了 useCallback
  2. 我们使用 useState 创建了一个状态变量 count
  3. 我们使用 useCallback 定义了一个 increment 函数。这个函数将增加我们的计数器。
  4. 空数组 [] 作为第二个参数意味着这个函数永远不会改变。
  5. 我们渲染我们的计数器和一个按钮,当点击时调用 increment

useCallback 的使用场景

现在你可能想知道,“我应该在什么时候使用 useCallback?”这是个好问题!让我们看看一些常见场景:

1. 向优化过的子组件传递回调

想象你有一个子组件被 React.memo 包裹(现在不用担心这个,我们将在未来的课程中介绍)。你想要向这个组件传递一个函数:

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

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

const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);

return (
<div>
<ChildComponent onClick={handleClick} />
<p>计数:{count}</p>
</div>
);
}

const ChildComponent = React.memo(({ onClick }) => {
console.log("子组件渲染了!");
return <button onClick={onClick}>增加</button>;
});

在这里,useCallback 确保只有当 count 改变时,handleClick 才会改变,从而防止 ChildComponent 不必要的重新渲染。

2. 在 useEffect 的依赖项中

useCallback 在函数是 useEffect 钩子的依赖项时也很有用:

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

function DataFetcher() {
const [data, setData] = useState(null);

const fetchData = useCallback(() => {
// 想象这是从 API 获取数据
setTimeout(() => setData("新数据!"), 1000);
}, []);

useEffect(() => {
fetchData();
}, [fetchData]);

return <div>{data ? data : "加载中..."}</div>;
}

在这个示例中,useCallback 确保在每次渲染时 fetchData 都不会改变,防止副作用不必要地运行。

优点和缺点

让我们总结一下 useCallback 的优点和缺点:

优点 缺点
防止不必要的重新渲染 可能会使代码更复杂
为子组件优化性能 过度使用可能会导致性能问题
useEffect 依赖项中有用 需要理解闭包和记忆化
帮助创建稳定的回调 在简单组件中可能不会提供显著的好处

结论

哇!我们今天涵盖了很多内容。useCallback 是你 React 工具箱中的强大工具,但就像任何工具一样,使用它要明智。在你继续你的 React 之旅时,你将培养出何时使用 useCallback 的直觉。

记住,优化是很好的,但清晰、可读的代码更重要。不要觉得有压力去到处使用 useCallback —— 在对你的应用程序有意义时使用它。

继续练习,保持好奇心,快乐编码!记住,就像完善饼干配方一样,掌握 React 需要时间和耐心。你能做到的!

Credits: Image by storyset