You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在客户端组件中使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:12:33