别再为 React 中的数据获取而苦恼 (React Day 7)
Source: Dev.to
请提供您想要翻译的具体文本内容(文章正文),我将为您翻译成简体中文。
(代码块、URL 和 Markdown 语法会保持原样不变。)
Fetch 基础
原生的 fetch API 已内置于浏览器中,并且使用 Promise 进行工作。
Axios 概述
Axios 是一个流行的 HTTP 客户端,提供了自动 JSON 解析、更好的错误处理、请求取消和拦截器等便利功能。
import axios from 'axios';
axios.get('https://api.example.com/data')
.then(res => console.log(res.data))
.catch(err => console.error(err));
Fetch 与 Axios
| 功能 | Fetch | Axios |
|---|---|---|
| 大小 | 内置(额外 0 KB) | 大约 13 KB(已压缩) |
| JSON 处理 | 手动 (res.json()) | 自动 |
| 错误处理 | 仅网络错误 | 网络错误 + HTTP 状态码(例如 404) |
| 取消请求 | 需要 AbortController | 内置取消令牌 |
| 适用场景 | 快速原型 | 需要认证、拦截器的生产应用 |
当你需要全局认证头、请求/响应拦截器或更健壮的错误处理时,请使用 Axios。
常见加载/错误模式
import { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => {
if (!res.ok) throw new Error('Fetch failed!');
return res.json();
})
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, []);
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<>
{data?.map(post => (
<div key={post.id}>- {post.title}</div>
))}
</>
);
}
管理加载 UI
- 当
loading为true时显示旋转加载图标或骨架屏。 - 当
error被设置时显示友好的错误信息。
useEffect 数据获取模式
| 场景 | 依赖数组 | 描述 |
|---|---|---|
| 挂载时获取 | [] | 首次渲染后运行一次。 |
| 依赖变化时重新获取 | [userId] | 每当 userId 变化时再次运行。 |
| 卸载时清理 | 返回函数 | 中止未完成的请求或取消订阅。 |
使用 AbortController 的中止示例
useEffect(() => {
const controller = new AbortController();
fetch('https://api.example.com/data', { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') setError(err);
});
return () => controller.abort();
}, []);
陷阱: 省略依赖数组会导致 effect 在每次渲染时运行,进而产生无限的获取循环。
实际场景
天气应用 (Axios)
useEffect(() => {
axios.get('https://api.openweathermap.org/data/2.5/weather', {
params: { q: 'Bengaluru', appid: process.env.REACT_APP_OWM_KEY }
})
.then(res => setWeather(res.data))
.catch(setError);
}, []);
无限滚动列表
- 当用户滚动接近底部时获取更多页面。
- 将新项目追加到现有状态,而不是替换。
- 通过跟踪当前页码来防止重复条目。
常见问题与解决方案
| 问题 | 原因 | 解决办法 |
|---|---|---|
| 数据重复 | 缺少页面跟踪 | 存储并递增页面计数器。 |
| 无限循环 | useEffect 中缺少依赖数组 | 添加适当的依赖项([] 或 [var])。 |
| 内存泄漏 | 卸载时未进行清理 | 在清理函数中中止请求或取消订阅。 |
| 闭包陈旧 | 省略了依赖项 | 在依赖数组中包含所有外部变量或使用函数式状态更新。 |
| 竞争条件 | 请求重叠 | 使用 AbortController 或 Axios 取消令牌取消之前的请求。 |
| 开发环境双重请求 | React StrictMode 会运行两次 effect | 接受这仅在开发时出现;确保清理工作正常。 |
性能技巧
- Debounce 在触发获取之前对快速输入变化进行防抖。
- 使用 IntersectionObserver 在无限滚动中实现懒加载。
- Cache 结果使用 React Query 或 SWR 等库,以避免不必要的网络调用。
- 在可能的情况下 Batch 多个请求。
- 通过 CDN 提供资源并启用 compression(gzip/Brotli)。
安全提醒
切勿将 API 密钥提交到源代码管理。将它们存储在环境变量(process.env.REACT_APP_...)中,并在运行时引用。
高级主题(简要概述)
- Error Boundaries – 将组件包装起来,以捕获因获取失败而导致的渲染错误。
- React Suspense – 使用 “ 实现面向未来的加载状态。
- Testing – 使用 MSW 或 jest-fetch-mock 模拟网络调用。
- Caching Strategies – 使用 stale‑while‑revalidate 模式实现快速 UI 更新。
进一步学习
- 视频教程:Data Fetching in React(在 YouTube 上搜索以获取完整的演练)。
您现在已经拥有了在 React 中获取数据的坚实基础——从基本的 fetch 调用到使用 Axios 的健壮模式、加载状态、清理以及性能考虑。尝试构建一个 GitHub 用户搜索器或任何基于 API 的功能,以巩固这些概念。祝编码愉快!