适用版本: React 19 + Vite + TypeScript
核心技术: Ky + TanStack Query
适用场景: 替代 Axios + 手写 useEffect 请求逻辑的现代方案
一、背景:从 Axios 到现代 Fetch 封装
过去我们常使用 Axios 处理请求,它提供了:
-
拦截器(interceptor)
-
超时控制
-
响应转换
-
请求取消
但现代浏览器的 Fetch API 已经非常强大,
如果能在其基础上进行更轻量的封装,将获得更好的兼容性与性能。
Ky 就是这样一款工具,它是对 fetch 的现代化封装,简洁、可扩展、TypeScript 友好。
再搭配 TanStack Query(即 react-query),就能轻松实现:
-
自动缓存与刷新
-
错误重试
-
加载状态管理
-
数据同步与失效机制
这两者组合,堪称"前端数据层的黄金搭档"。
二、Ky 简介:轻量级的 Fetch 封装
1. 安装
npm install ky
或
yarn add ky
2. 基本使用
javascript
import ky from 'ky';
const data = await ky.get('/api/users').json();
这行代码已经等价于:
javascript
const res = await fetch('/api/users');
const data = await res.json();
但 Ky 提供了:
-
自动抛出错误(非 2xx 响应)
-
直接解析 JSON
-
更简洁的 API 语法
三、创建 Ky 实例(封装请求层)
为了支持 Token、Base URL、统一错误处理等,我们可以创建一个自定义实例:
javascript
// src/api/kyInstance.ts
import ky from 'ky';
const api = ky.create({
prefixUrl: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
credentials: 'include',
hooks: {
beforeRequest: [
request => {
const token = localStorage.getItem('token');
if (token) {
request.headers.set('Authorization', `Bearer ${token}`);
}
},
],
afterResponse: [
async (_request, _options, response) => {
if (response.status === 401) {
// 自动登出或跳转登录页
window.location.href = '/login';
}
},
],
},
});
export default api;
使用示例:
javascript
// src/api/user.ts
import api from './kyInstance';
export const getUser = () => api.get('user/profile').json<User>();
export const updateUser = (data: Partial<User>) =>
api.patch('user/profile', { json: data }).json<User>();
Ky 设计哲学就是------fetch but better 。
保持简洁,不额外造轮子。
四、TanStack Query:智能的数据层管理
Ky 负责 请求 ,而 TanStack Query 负责 状态与缓存 。
我们再也不用在组件里管理 loading、error、refresh 逻辑了。
1. 安装
bash
npm install @tanstack/react-query
2. 配置 QueryClient
javascript
// src/main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import ReactDOM from 'react-dom/client';
import App from './App';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
五、结合使用:Ky + TanStack Query 实战
假设我们要在页面中显示用户信息:
javascript
// src/pages/Profile.tsx
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { getUser, updateUser } from '@/api/user';
export default function Profile() {
const queryClient = useQueryClient();
const { data, isLoading, isError } = useQuery({
queryKey: ['user'],
queryFn: getUser,
});
const mutation = useMutation({
mutationFn: updateUser,
onSuccess: () => {
// 更新缓存
queryClient.invalidateQueries({ queryKey: ['user'] });
},
});
if (isLoading) return <p>加载中...</p>;
if (isError) return <p>加载失败</p>;
return (
<div className="p-4">
<h1>👤 用户资料</h1>
<p>姓名:{data.name}</p>
<button
onClick={() => mutation.mutate({ name: '新名字' })}
className="mt-2 px-3 py-1 bg-blue-500 text-white rounded"
>
修改姓名
</button>
</div>
);
}
这样,我们就实现了:
-
自动缓存用户信息
-
更新后自动刷新
-
异步状态统一管理
-
Ky 提供更优雅的请求层
六、进阶技巧:错误处理 + 请求重试 + 全局 Loading
1. 全局错误处理
可在 QueryClient 中定义默认行为:
javascript
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 2,
refetchOnWindowFocus: false,
onError: error => {
console.error('Query Error:', error);
},
},
},
});
2. 全局 Loading 监控
javascript
import { useIsFetching } from '@tanstack/react-query';
function GlobalLoading() {
const isFetching = useIsFetching();
return isFetching ? <div className="loading-bar" /> : null;
}
可在根组件中挂载,实现任意请求时的 Loading 条。
七、Ky vs Axios 对比总结
| 特性 | Ky | Axios |
|---|---|---|
| 基于 | Fetch | XHR |
| 体积 | 小(~7KB) | 大(~20KB) |
| 支持拦截器 | ✅ Hooks机制 | ✅ 拦截器 |
| TypeScript 支持 | ✅ 原生 | ✅ 完善 |
| 超时控制 | ✅ 内置 | ✅ 内置 |
| JSON 解析 | ✅ 一行搞定 | ❌ 手动解析 |
| 语法风格 | 函数式、现代 | 面向对象式 |
| Node.js 支持 | ❌(需 polyfill) | ✅ |
如果你的项目是纯前端 SPA,Ky 是更优雅、现代的选择。
若要兼容 SSR 或 Node 环境,Axios 仍有优势。
八、总结
通过 Ky + TanStack Query 的组合,我们获得了:
更轻量的请求层 :基于 Fetch,无需冗余 polyfill
智能的状态管理 :数据缓存、失效、自动刷新
清晰的分层结构 :API 层(Ky) + 数据层(Query)
可扩展性强:全局错误处理、重试策略、登录失效处理