Next.js 13:搜索参数变更时如何触发加载UI?
解决Next.js搜索参数变更不触发loading.tsx的问题
问题场景
当前组件通过router.push更新URL搜索参数,能正常触发数据更新和UI渲染,但对应路由的loading.tsx加载界面不会触发显示,需求是保留带搜索参数的URL,同时让搜索参数变更时触发加载状态。
核心原因
Next.js默认将搜索参数变更视为同页面的客户端状态更新,不会触发服务器组件的重新加载流程,因此loading.tsx(仅在服务器组件加载阶段显示)不会被激活。
可行解决方案
方案1:强制导航时重新验证(App Router 适用)
在router.push中添加forceRevalidate: true选项,强制触发服务器组件的重新渲染,从而激活loading.tsx:
const updateParams = (category: string | number, subcategory: string | number) => { searchParams.set("category", String(category)); searchParams.set("subcategory", String(subcategory)); router.push(`/my-url/?${searchParams.toString()}`, { forceRevalidate: true, // 强制重新验证并加载服务器组件 }); };
方案2:手动维护加载状态
如果方案1无法满足需求,可以在组件内手动控制加载状态,在搜索参数更新期间显示自定义加载UI(可复用loading.tsx的内容):
const MyComponent = (props: Props) => { const router = useRouter(); const searchParams = new URLSearchParams(Array.from(useSearchParams().entries())); const [isLoading, setIsLoading] = useState(false); const form = useForm({ defaultValues: { category: searchParams.get("category") || NaN, subcategory: searchParams.get("subcategory") || NaN, }, }); const category = form.watch("category"); const subcategory = form.watch("subcategory"); const updateParams = async (category: string | number, subcategory: string | number) => { setIsLoading(true); searchParams.set("category", String(category)); searchParams.set("subcategory", String(subcategory)); try { await router.push(`/my-url/?${searchParams.toString()}`, { forceRevalidate: true }); } finally { // 可根据数据加载完成事件调整时机,比如监听新数据获取完成后再关闭加载状态 setIsLoading(false); } }; useEffect(() => { if (subcategory) { updateParams(category, subcategory); } }, [subcategory, category]); // 优先显示加载状态 if (isLoading) { return <div>加载中...</div>; // 替换为loading.tsx的内容 } // 原组件渲染逻辑 return (...); };
注意事项
- 修正原代码变量顺序问题:
const category = form.watch("category");需放在useEffect之前,避免依赖未定义的变量。 - 确保页面组件为服务器组件,且数据获取逻辑依赖搜索参数,这样强制重新验证时才能触发正确的加载流程。
内容的提问来源于stack exchange,提问作者Vitor Figueredo Marques
相关产品推荐
相关产品推荐

