如何在客户端组件中使用useQuery重新获取项目列表数据
解决方案:创建项目后自动刷新React Query列表
问题根源
你之前用if(isSuccess) { refetch(); }导致无限调用,是因为每次refetch成功后,isSuccess会再次变为true,触发组件重新渲染,进而再次调用refetch,形成死循环。
正确实现步骤
1. 从useQuery中解构refetch方法
先在项目页面组件里,把refetch从useQuery的返回值里解构出来:
"use client"; import React from "react"; import {DataTable} from "./dataTable"; import {columns} from "./columns"; import {getProjectLists} from "@/app/api/projectActions"; import {useQuery} from "@tanstack/react-query"; import {Button} from "@/components/ui/button"; // 假设你的弹窗组件是CreateProjectModal import CreateProjectModal from "./CreateProjectModal"; const ProjectPage = () => { // 解构出refetch方法 const {data, isError, isLoading, error, refetch} = useQuery({ queryKey: ["projects"], queryFn: () => getProjectLists(1, 10), }); console.log("data", data); if (isLoading) { return <div className="text-center">Loading...</div>; } return ( <div className="w-4/5 mx-auto py-10"> {/* 把refetch传给弹窗组件 */} <CreateProjectModal onProjectCreated={refetch} /> {data && <DataTable columns={columns} data={data} />} <Button> {/* (This should something like infinite scroll. check react-query for code) */} Load More </Button> </div> ); }; export default ProjectPage;
2. 在弹窗提交成功后调用refetch
在你的创建项目弹窗组件里,当表单提交、创建项目的API调用成功后,调用传入的onProjectCreated(也就是refetch):
"use client"; import React, { useState } from "react"; import { createProject } from "@/app/api/projectActions"; import { Button } from "@/components/ui/button"; const CreateProjectModal = ({ onProjectCreated }) => { const [isOpen, setIsOpen] = useState(false); const [projectName, setProjectName] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); try { // 调用创建项目的API await createProject({ name: projectName }); // 创建成功后调用refetch刷新列表 await onProjectCreated(); // 关闭弹窗 setIsOpen(false); // 重置表单 setProjectName(""); } catch (err) { console.error("创建项目失败:", err); } }; return ( <> <Button onClick={() => setIsOpen(true)}>创建项目</Button> {isOpen && ( <div className="fixed inset-0 bg-black/50 flex items-center justify-center"> <div className="bg-white p-6 rounded-lg"> <form onSubmit={handleSubmit}> <input type="text" value={projectName} onChange={(e) => setProjectName(e.target.value)} placeholder="输入项目名称" required /> <div className="mt-4 flex gap-2"> <Button type="submit">提交</Button> <Button type="button" onClick={() => setIsOpen(false)}>取消</Button> </div> </form> </div> </div> )} </> ); }; export default CreateProjectModal;
3. 备选方案:使用invalidateQueries
除了直接调用refetch,你也可以在弹窗提交成功后,调用invalidateQueries让React Query自动重新获取数据:
// 在弹窗组件里导入useQueryClient import { useQueryClient } from "@tanstack/react-query"; const CreateProjectModal = () => { const queryClient = useQueryClient(); const handleSubmit = async (e) => { e.preventDefault(); try { await createProject({ name: projectName }); // 使projects缓存失效,React Query会自动重新获取 await queryClient.invalidateQueries({ queryKey: ["projects"] }); setIsOpen(false); setProjectName(""); } catch (err) { console.error("创建项目失败:", err); } }; // ...其余代码 };
为什么之前的方法无效?
revalidatePath('/projects'):这是Next.js App Router的服务端方法,只能在服务端组件或Server Action中使用,客户端组件调用无效。redirect('/projects'):在客户端组件中需要用useRouter钩子的push方法,直接调用redirect不会生效。window.location.reload():服务端组件中没有window对象,所以调用会报错;如果是客户端组件,虽然能生效,但这是强制刷新页面,体验不如React Query的局部刷新。
内容的提问来源于stack exchange,提问作者aRtoo
相关产品推荐
相关产品推荐

