引言
在 React 开发中,自定义 Hooks 是提取组件逻辑、实现代码复用的强大工具。上篇文章我们介绍了自定义 Hooks 的基本概念,今天我们将深入三个实用的自定义 Hooks:useFetch、useDebounce和useInterval,看看它们如何解决实际开发中的常见问题。
1. useFetch - 优雅的数据获取
使用场景
处理 API 请求时,我们需要管理加载状态、错误处理和响应数据。useFetch 将这些逻辑封装成一个可复用的 Hook。
完整实现
typescript
import { useState, useEffect } from 'react';
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
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 (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
使用示例
javascript
function UserProfile({ userId }: { userId: string }) {
const { data, loading, error } = useFetch<User>(
`/api/users/${userId}`
);
if (loading) return <div>加载中...</div>;
if (error) return <div>错误:{error.message}</div>;
if (!data) return null;
return (
<div>
<h1>{data.name}</h1>
<p>{data.email}</p>
</div>
);
}
2. useDebounce - 防抖优化
使用场景
在搜索框输入、窗口大小调整等高频触发场景中,useDebounce 可以延迟执行,避免不必要的计算和请求。
完整实现
typescript
import { useState, useEffect } from 'react';
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(timer);
};
}, [value, delay]);
return debouncedValue;
}
使用示例
ini
function SearchBox() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
// 只在用户停止输入 500ms 后执行搜索
if (debouncedSearchTerm) {
fetchSearchResults(debouncedSearchTerm);
}
}, [debouncedSearchTerm]);
return (
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="搜索..."
/>
);
}
3. useInterval - 定时器 Hook
使用场景
需要周期性执行某些操作(如轮询、动画、倒计时)时,useInterval 提供了声明式的定时器管理。
完整实现
javascript
import { useEffect, useRef } from 'react';
function useInterval(callback: () => void, delay: number | null) {
const savedCallback = useRef<() => void>();
// 记住最新的回调函数
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// 设置定时器
useEffect(() => {
function tick() {
savedCallback.current?.();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
使用示例
scss
function Counter() {
const [count, setCount] = useState(0);
useInterval(() => {
setCount(count + 1);
}, 1000);
return <div>计数:{count}</div>;
}
总结对比
| Hook | 核心用途 | 关键特性 | 典型场景 |
|---|---|---|---|
useFetch |
数据获取 | 自动管理 loading/error/state | API 调用、数据加载 |
useDebounce |
防抖优化 | 延迟值更新、自动清理定时器 | 搜索框、输入验证 |
useInterval |
定时执行 | 支持动态延迟、自动清理 | 轮询、动画、倒计时 |
最佳实践建议
- 命名规范 :自定义 Hook 必须以
use开头 - 依赖管理 :确保
useEffect依赖数组完整 - 清理副作用:返回清理函数避免内存泄漏
- 类型安全:使用 TypeScript 泛型提高类型推断
- 测试覆盖:为自定义 Hook 编写单元测试