如果你在做 react 项目,并且需要从后端获取数据,那你很可能遇到过这些情况:
同样的数据在不同组件里重复请求
用户操作后,界面数据没有及时更新
加载状态和错误状态需要自己处理
分页、无限滚动等功能实现起来很麻烦
@tanstack/react-query(原名 React Query)就是专门为解决这些问题而生的。它是一个专门管理服务器状态的数据获取库。
简单来说,react-query 帮你处理所有跟后台数据相关的工作:
自动缓存数据,避免重复请求
数据过期后自动重新获取
错误自动重试
乐观更新(先更新界面,再发送请求)
分页和无限滚动支持
你不再需要把这些逻辑写在 Redux 或者 Context 里,代码会简洁很多。
安装:
pnpm add @tanstack/react-query
在应用最外层设置:
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Layout from '@/Layout';
export default function App() {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<Layout />
</QueryClientProvider>
);
}
这样你的所有组件就都能使用 react-query 的功能了。
看一个获取用户信息的例子:
import React from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
// 定义获取数据的函数
function fetchUser(userId) {
return axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(res => res.data);
}
function User({ userId }) {
const { data, isLoading, isError, error, refetch } = useQuery({
queryKey: ['user', userId], // 缓存的键名
queryFn: () => fetchUser(userId), // 获取数据的函数
staleTime: 1000 * 60, // 1分钟内数据是新鲜的,不会重新请求
cacheTime: 1000 * 60 * 5, // 数据缓存5分钟
retry: 2, // 失败自动重试2次
});
if (isLoading) return <div>加载中...</div>;
if (isError) return <div>出错了: {error.message}</div>;
return (
<div>
<h2>{data.name}</h2>
<p>邮箱: {data.email}</p>
<button onClick={() => refetch()}>重新加载</button>
</div>
);
}
这里有几个重要的参数:
queryKey:数据的唯一标识,相同 key 的数据会被缓存和复用
staleTime:数据保鲜时间,这段时间内不会重新请求
cacheTime:数据缓存时间,即使组件卸载了数据还会保留
当你需要添加、修改或删除数据时,可以用 useMutation:
import React, { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
// 获取待办列表
const fetchTodos = () => axios.get('/api/todos').then(res => res.data);
// 添加新待办
const addTodo = (text) => axios.post('/api/todos', { text }).then(res => res.data);
export function Todos() {
const queryClient = useQueryClient();
const [newText, setNewText] = useState('');
// 获取待办列表
const { data: todos = [] } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos
});
// 添加新待办
const mutation = useMutation({
mutationFn: addTodo,
// 乐观更新:先更新界面,再发送请求
onMutate: async (text) => {
// 取消正在进行的请求,避免冲突
await queryClient.cancelQueries({ queryKey: ['todos'] });
// 保存当前数据,用于出错时回滚
const previousTodos = queryClient.getQueryData(['todos']);
// 立即更新缓存
queryClient.setQueryData(['todos'], [...(previousTodos || []), {
id: Date.now(),
text,
// 临时标识,等真实请求成功后会替换
optimistic: true
}]);
return { previousTodos };
},
// 出错时回滚到之前的状态
onError: (err, variables, context) => {
if (context?.previousTodos) {
queryClient.setQueryData(['todos'], context.previousTodos);
}
},
// 无论成功失败,都重新获取最新数据
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
}
});
return (
<div>
<h2>待办列表</h2>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
{todo.optimistic && ' (保存中...)'}
</li>
))}
</ul>
<input
value={newText}
onChange={e => setNewText(e.target.value)}
placeholder="输入新待办"
/>
<button onClick={() => mutation.mutate(newText)}>
添加
</button>
</div>
);
}
乐观更新让用户体验更好,用户不用等待请求完成就能看到结果。
有时候你需要先获取一个数据,然后基于这个数据获取另一个数据:
// 先获取用户信息
const userQuery = useQuery({
queryKey: ['userByName', username],
queryFn: () => axios.get(`/api/users?username=${username}`).then(res => res.data),
});
// 等获取到用户ID后,再获取用户的文章
const postsQuery = useQuery({
queryKey: ['posts', userQuery.data?.id],
queryFn: () => axios.get(`/api/users/${userQuery.data.id}/posts`).then(res => res.data),
// 只有拿到用户ID后才执行
enabled: !!userQuery.data?.id,
});
enabled 参数让你能够控制什么时候执行请求。
react-query 提供了开发工具,让你在开发时能看到缓存的数据、正在进行的请求等信息:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Layout />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
安装开发工具包:
pnpm add @tanstack/react-query-devtools
统一管理查询键名:把所有的 queryKey 放在一个文件里管理,避免拼写错误
封装自定义 Hooks:把 useQuery 和 useMutation 封装成自定义 Hook,方便复用
设置全局默认值:可以配置默认的 staleTime 和 cacheTime
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5分钟
cacheTime: 1000 * 60 * 30, // 30分钟
},
},
});
@tanstack/react-query 解决了 React 项目中数据管理的核心问题。它让你的代码更简洁,用户体验更好,开发效率更高。虽然需要一些学习成本,但一旦用起来,你会发现它大大简化了数据获取和状态管理的工作。
如果你的项目中有复杂的数据获取需求,或者你厌倦了自己处理加载状态和缓存逻辑,那么很值得尝试一下 react-query。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
在当今的专业环境中,项目经理需要戴上各种帽子,在管理团队的日常功能和理解大局策略之间切换。正因为如此,项目经理对组织变得更有价值,并且他们对技能和战略角色的需求在全球范围内不断增长。但这也提出了一个问题:如何在如此高压的环境中成为更好的项目经理?
随机产生规定范围内的整数,然后再产生相同范围内的整数,两者相同时,则暂停。所用知识:Math.random() * num: 产生从0到num的随机数,Math.floor(): 向下取整,简单的DOM操作等
我马上就要毕业了没有开发经验怎么办?我投递了 N 多公司全部没有给工作机会,有的给了面试机会也是没有下文了怎么办?我简历上什么东西都没有,要不要伪造一个工作经历呢?
项目经理这个神奇的职位,改变了我很多工作处事的方式,从前性情纯真的耿直boy,现在变成了人鬼皆爱的老油条, 以下是我当了项目经理之后明白的10件事, 如有雷同,真是太巧。
pm2 大家应该都知道,主要是用来管理 node 进程,但是同样可以用来部署前端代码。也可以手动添加 public key 到服务器上的 ~/.ssh/authorized_keys,
我不是专业的项目经理,这里不讨论大型项目管理的事情。我们比较常遇到的可能是小型的长周期项目,比如2-4个人,做半年甚至一年的项目。这种项目通常不会有专职的项目经理
通过 attachShadow 这个方法生成一个shadow root 即shadow的根节点,然后在这个根节点下面通过循环语句添加水印,利用position为absolute进行排版,使其铺满容器
我相信每个接受过老项目的程序员可能都吐槽过“前人的代码都是屎”。一个已经有些年头的项目,几乎肯定可以看到——到处拷贝来拷贝去的代码,随处可见的拼写错误,头重脚轻的函数……
近几年随着微服务化项目的崛起,逐渐成为许多公司中大型分布式系统架构的主流方式,而今天所说的 RPC 在这其中扮演着至关重要的角色。随着这段日子公司项目微服务化的演进,发现在日常开发中都在隐式或显式的使用 RPC
首先搭建vue项目,lint选择ESLint + Prettier,配置方式选择In dedicated config files。具体搭建过程这里就不赘述了,如果不熟悉的同学可以点击这里。配置 Stylelint,目前还没有stylelint选项,需要我们自己安装相关的 npm 包
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!