跟useMemo有点像,但是主要用于在 React 组件中缓存函数,特别是当这些函数被当作 props 传递给子组件,或者用于事件处理和触发重新渲染时。这样可以避免在组件的每次重新渲染时创建新的函数实例,从而优化性能。
基本使用
import React, { useCallback } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = ({ itemId }) => {
const handleClick = useCallback(() => {
console.log(`Clicked on item ${itemId}`);
}, [itemId]);
return <ChildComponent onClick={handleClick} />;
};
与 useEffect 搭配
还可以与useEffect一起使用
import React, { useState, useCallback, useEffect } from 'react';
const MyComponent = ({ userId }) => {
const [query, setQuery] = useState('');
const fetchData = useCallback(async () => {
const url = `https://api.example.com/data?user=${userId}&query=${query}`;
const response = await fetch(url);
const data = await response.json();
console.log('Data fetched:', data);
}, [userId, query]); // `fetchData` 现在依赖于 userId 和 query
useEffect(() => {
fetchData();
}, [fetchData]); // 仅在 `fetchData` 发生变化时调用一次
return (
<div>
<input type="text" value={query} onChange={(e) => setQuery(e.target.value)} />
<button onClick={fetchData}>Search</button>
</div>
);
};
以上代码就是当搜索输入框进行输入操作时,调用setQuery,useCallback的依赖发生变化时,会进行函数的再次执行。
那么这里引申出一个问题
问题
useEffect的依赖中放fetchData(经过useCallback处理的函数),有什么用,直接放query不行吗?
回答一 :
fetchData 是通过 useCallback 创建的一个被缓存的函数。尽管 fetchData 是一个函数,但它的引用可以在不同的渲染之间变化。当 useCallback 的依赖数组中的项发生变化时,它会返回一个新的函数实例。在例子中,fetchData 依赖于 query,这意味着每当 query 改变时,fetchData 就会变成一个新的引用。这就是为什么说 fetchData 可以变化的原因。
回答二 :
以上实例代码不是完整的业务代码,如果仅仅是 query 变化就重新执行搜索,那不搭配使用也可以,但是useCallback的本质是执行一个函数,在这个搜索框的 onChange 方法被触发时,不能立即请求,等用户输入完再进行请求,所以在这里要使用一个防抖函数,输入后等待一段时间才判定输入完成,这样可以减少网络的请求次数。
import React, { useState, useCallback } from 'react';
// 简单的防抖函数实现
const debounce = (func, delay) => {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
};
const MyComponent = ({ userId }) => {
const [query, setQuery] = useState('');
const fetchData = useCallback(async () => {
const url = `https://api.example.com/data?user=${userId}&query=${query}`;
const response = await fetch(url);
const data = await response.json();
console.log('Data fetched:', data);
}, [userId, query]); // `fetchData` 现在依赖于 userId 和 query
// 使用防抖函数包装 handleChange
const handleChange = debounce((event) => {
setQuery(event.target.value);
}, 300); // 延迟 300ms
return (
<div>
<input type="text" value={query} onChange={handleChange} />
</div>
);
};
定义了一个名为 debounce 的函数,它接受一个函数和一个延迟时间作为参数,返回一个新的函数。这个新的函数在被调用时会等待一段时间,如果在这段时间内再次被调用,旧的定时器会被清除,然后重新设置一个新的定时器,以确保在延迟时间结束后才会执行函数。