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

Next.js中如何通过router.push()和router.refresh()即时更新URL参数并在数据获取时显示加载器

Next.js中如何通过router.push()和router.refresh()即时更新URL参数并在数据获取时显示加载器

我来帮你梳理下问题,然后一步步解决这个URL更新延迟和加载状态的问题。首先得明确:正常情况下router.push()应该是立即更新浏览器地址栏的,你感觉到的3秒延迟大概率是混淆了URL更新和后端数据加载完成的时间——URL其实已经变了,但页面在等新数据渲染,所以你误以为URL没更新。下面是具体的优化方案:


一、先解决URL即时更新的问题

你的WorkflowTable.jsx里的参数处理可能有小问题,导致导航操作被阻塞。我们用Next.js App Router的标准工具来修正:

'use client';

import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { useState, useCallback, useEffect } from 'react';

const WorkflowTable = ({ data, columns, toolbarConfig, pagination, filterObject, folderSelectedID }) => {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [isLoading, setIsLoading] = useState(false);

  // 用useCallback确保函数不会频繁重创建,避免不必要的渲染延迟
  const handleUrlForPage = useCallback((index) => {
    const pageNo = index + 1;
    // 先设置加载状态(用户能立即看到反馈)
    setIsLoading(true);

    // 复制当前搜索参数(原searchParams是只读对象,不能直接修改)
    const newParams = new URLSearchParams(searchParams);
    if (pageNo) {
      newParams.set('page', pageNo.toString());
    } else {
      newParams.delete('page');
    }

    // 执行导航:这里会立即更新浏览器地址栏
    router.push(`${pathname}?${newParams.toString()}`, { scroll: false });
  }, [router, pathname, searchParams]);

  // 当服务器组件返回新数据(props更新),关闭加载状态
  useEffect(() => {
    if (isLoading) {
      setIsLoading(false);
    }
  }, [pagination.pageIndex, data]);

  return (
    <div className="relative">
      {/* 表格加载遮罩:点击页码后立即显示 */}
      {isLoading && (
        <div className="absolute inset-0 bg-white/80 flex items-center justify-center z-10">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
        </div>
      )}
      {/* 你的表格渲染代码 */}
      {/* ... */}
    </div>
  );
};

export default WorkflowTable;

关键修正点:

  1. 复制搜索参数:原searchParams是只读的,直接修改会导致异常,用new URLSearchParams(searchParams)创建可修改的副本。
  2. useCallback优化:避免handleUrlForPage函数每次渲染都重新创建,减少不必要的组件重渲染延迟。
  3. scroll: false:导航时禁止自动滚动到顶部,提升用户体验。

二、全局加载状态(可选)

如果你想在整个Workflow页面显示加载提示(比如全屏遮罩),可以把加载状态提升到Workflow.jsx组件:

'use client';

import { useState, useEffect } from 'react';
import WorkflowTable from "../../_components/_workflow/WorkflowTable";
import DashboardWrapper from "../../_components/DashboardWrapper";
import { workflowColumns } from "../../_components/_workflow/workflowColumns";
import { formatWorkflowTableData } from "@/lib/utils";

export default function Workflow({ workflowResponse, filterObject, toolbarConfig, classes, folderSelectedID }) {
  const [isLoading, setIsLoading] = useState(false);

  // 监听page参数变化,开始加载
  useEffect(() => {
    setIsLoading(true);
    // 当workflowResponse更新(服务器组件返回新数据),关闭加载
    const cleanup = setTimeout(() => setIsLoading(false), 100);
    return () => clearTimeout(cleanup);
  }, [filterObject.current_page]);

  // 或者直接监听workflowResponse的变化,更准确
  useEffect(() => {
    setIsLoading(false);
  }, [workflowResponse]);

  return (
    <DashboardWrapper className={classes ? classes : ""}>
      {/* 全屏加载遮罩 */}
      {isLoading && (
        <div className="fixed inset-0 bg-black/20 flex items-center justify-center z-50">
          <div className="bg-white p-4 rounded-lg shadow-lg">
            <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-800 mx-auto"></div>
            <p className="mt-2 text-sm text-gray-700">加载中...</p>
          </div>
        </div>
      )}
      <div className="flex h-full flex-1 flex-col space-y-6">
        <WorkflowTable
          data={formatWorkflowTableData(workflowResponse?.data)}
          columns={workflowColumns(toolbarConfig)}
          toolbarConfig={toolbarConfig}
          pagination={{
            pageIndex: workflowResponse?.current_page - 1,
            pageSize: workflowResponse?.total_pages,
            totalData: workflowResponse?.total,
          }}
          filterObject={filterObject}
          folderSelectedID={folderSelectedID}
        />
      </div>
    </DashboardWrapper>
  );
}

三、如果还是遇到数据更新延迟:用router.refresh()

如果导航后服务器组件的数据没有自动更新(比如缓存问题),可以在router.push之后调用router.refresh()强制刷新服务器组件:

// 在handleUrlForPage里添加
router.push(`${pathname}?${newParams.toString()}`, { scroll: false }).then(() => {
  router.refresh();
});

不过App Router通常会根据URL参数自动重新渲染服务器组件,这个操作只作为兜底方案。


最后总结

  • URL更新延迟:本质是之前的参数处理有误,修正后router.push()会立即更新地址栏。
  • 加载状态:在客户端组件中维护isLoading状态,点击页码时开启,服务器组件返回新数据时关闭,给用户明确的加载反馈。

备注:内容来源于stack exchange,提问作者Kavan Prajapati

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 16:59:50