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;
关键修正点:
- 复制搜索参数:原
searchParams是只读的,直接修改会导致异常,用new URLSearchParams(searchParams)创建可修改的副本。 - useCallback优化:避免
handleUrlForPage函数每次渲染都重新创建,减少不必要的组件重渲染延迟。 - 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
相关产品推荐
相关产品推荐

