创建自定义 Hook:
-
以 "use" 开头的函数名:
- 自定义 Hook 的函数名称应该以 "use" 开头,这是 React 的约定,以便开发者识别它们是 Hook。
-
提取状态逻辑:
- 将要共享的状态逻辑从组件中提取到自定义 Hook 中。
示例:GET请求hook
import { useState, useEffect } from 'react';
function useHttpGet(url) {
// 定义状态
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// 发起 GET 请求
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]); // 仅在 url 发生变化时触发 useEffect
// 返回状态和重新发起请求的函数
return { data, loading, error, refetch: () => fetchData() };
}
// 使用自定义 Hook 的组件
function MyComponent() {
const { data, loading, error, refetch } = useHttpGet('<https://api.example.com/data>');
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Error: {error.message}</p>;
}
return (
<div>
{/* 使用获取到的数据 */}
<p>Data: {JSON.stringify(data)}</p>
{/* 提供重新发起请求的按钮 */}
<button onClick={refetch}>Refetch Data</button>
</div>
);
}
示例:防抖hook
function useDebounce(fn, delay, dep = []) {
// 使用 useRef 创建 current 对象 ,用于存储 当前目标函数 和 定时器
const { current } = useRef({ fn, timer: null });
// 使用 useEffect 监听 fn 参数的变化,更新 当前目标函数
useEffect(function () {
current.fn = fn;
}, [fn]);
// 返回一个使用 useCallback 创建的防抖函数 f
return useCallback(function f(...args) {
// 如果存在已计划的定时器,取消它
if (current.timer) {
clearTimeout(current.timer);
}
// 设置一个新的定时器,延迟 delay 毫秒后执行 当前目标函数
current.timer = setTimeout(() => {
current.fn.call(this, ...args);
}, delay);
// 通过 dep 作为依赖项传递给 useCallback,以确保在依赖项变化时重新创建防抖函数
}, dep)
}
💡 思路:
-
useDebounce接受三个参数:fn: 要防抖的函数,即希望延迟执行的函数。delay: 防抖的延迟时间,单位是毫秒。dep(可选): 依赖数组,用于在useCallback内部的useEffect钩子中。它允许你控制防抖函数的依赖项,以便在特定依赖项变化时重置防抖。
-
使用
useRef存储当前目标函数fn和定时器timer【用于延迟执行】 -
使用
useEffect监听fn参数的变化。如果fn发生变化,将更新当前目标函数。 -
返回一个使用
useCallback创建的函数f,它是防抖函数。-
在
f函数内部,首先检查是否存在已经计划的定时器(current.timer),如果有的话,使用clearTimeout取消之前的定时器。 -
然后,设置一个新的定时器,等待指定的
delay时间后执行当前目标函数current.fn。这确保了只有最后一次触发f函数会实际执行fn函数。 -
最后,将
dep作为依赖项传递给useCallback,以确保在依赖项变化时重新创建f函数。这是为了处理特殊情况,如果你想在某些依赖项变化时重置防抖函数的状态,可以在dep数组中列出这些依赖项。
-
示例:节流hook
function useThrottle(fn, delay, dep = []) {
// 使用 useRef 创建 current 对象 ,用于存储 当前目标函数 和 定时器
const { current } = useRef({ fn, timer: null });
// 使用 useEffect 监听 fn 参数的变化,更新 当前目标函数
useEffect(function () {
current.fn = fn;
}, [fn]);
// 返回一个使用 useCallback 创建的节流函数 f
return useCallback(function f(...args) {
// 如果没有定时器,则设置一个定时器以延迟执行
if (!current.timer) {
current.timer = setTimeout(() => {
// 清除定时器引用,允许下次触发
delete current.timer;
}, delay);
// 执行最新的函数(current.fn)
current.fn.call(this, ...args);
}
// 通过 dep 作为依赖项传递给 useCallback,以确保在依赖项变化时重新创建节流函数
}, dep);
}
💡 思路:
-
useThrottle接受三个参数:fn: 要节流的函数,即希望在指定时间间隔内执行的函数。delay: 节流的时间间隔,以毫秒为单位。dep(可选): 依赖数组,用于在useCallback内部的useEffect钩子中。它允许你控制节流函数的依赖项,以便在特定依赖项变化时重新创建节流函数。
-
使用
useRef存储当前目标函数fn和定时器timer【用于禁止执行】 -
使用
useEffect监听fn参数的变化。如果fn发生变化,将更新当前目标函数。 -
返回一个使用
useCallback创建的函数f,它是节流函数。-
在
f函数内部,首先检查是否存在已经计划的定时器(current.timer)。如果没有定时器,说明已经过去了指定的间隔时间:-
创建一个新的定时器来禁止函数执行。在新定时器中,等待指定的
delay时间后清除current.timer的引用,以允许下次触发。 -
执行当前目标函数
current.fn,这确保了间隔时间内只有第一次触发f函数会实际执行函数。
-
-
最后,将
dep作为依赖项传递给useCallback,以确保在依赖项变化时重新创建节流函数。这是为了处理特殊情况,如果你想在某些依赖项变化时重置节流函数的状态,可以在dep数组中列出这些依赖项。
-