在 React 项目中使用 Ky 与 TanStack Query 构建现代化数据请求层
适用版本: 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. 基本使用
import ky from 'ky';const data = await ky.get('/api/users').json();
这行代码已经等价于:
const res = await fetch('/api/users');
const data = await res.json();
但 Ky 提供了:
-
自动抛出错误(非 2xx 响应)
-
直接解析 JSON
-
更简洁的 API 语法
三、创建 Ky 实例(封装请求层)
为了支持 Token、Base URL、统一错误处理等,我们可以创建一个自定义实例:
// 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;
使用示例:
// 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. 安装
npm install @tanstack/react-query
2. 配置 QueryClient
// 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 实战
假设我们要在页面中显示用户信息:
// 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><buttononClick={() => mutation.mutate({ name: '新名字' })}className="mt-2 px-3 py-1 bg-blue-500 text-white rounded">修改姓名</button></div>);
}
这样,我们就实现了:
-
自动缓存用户信息
-
更新后自动刷新
-
异步状态统一管理
-
Ky 提供更优雅的请求层
六、进阶技巧:错误处理 + 请求重试 + 全局 Loading
1. 全局错误处理
可在 QueryClient 中定义默认行为:
const queryClient = new QueryClient({defaultOptions: {queries: {retry: 2,refetchOnWindowFocus: false,onError: error => {console.error('Query Error:', error);},},},
});
2. 全局 Loading 监控
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)
可扩展性强:全局错误处理、重试策略、登录失效处理
延伸阅读
-
Ky 官方文档
-
TanStack Query 官方文档
-
React 19 文档
-
Vite 官方网站
