Next.js 13中useRouter的push方法不再异步,如何维护加载状态?
Next.js 13中useRouter.push异步导航状态跟踪方案
Next.js 13 App Router的useRouter.push不再返回Promise,没法通过.then()监听导航完成状态,导致无法精准控制loading spinner的显示/隐藏。以下是几个实用的解决办法:
1. 用React的useTransition钩子(官方推荐)
useTransition是React专门处理过渡状态的API,完美适配App Router的导航逻辑,能自动跟踪导航的pending状态。
代码示例(本地状态)
import { useRouter } from 'next/navigation'; import { useTransition } from 'react'; const RedirectButton = ({ href }: { href: string }) => { const router = useRouter(); const [isPending, startTransition] = useTransition(); const handleRedirect = () => { startTransition(() => { router.push(href); }); }; return ( <button onClick={handleRedirect} disabled={isPending}> {isPending ? '跳转中...' : '立即跳转'} </button> ); };
结合状态管理(比如Redux)
import { useRouter } from 'next/navigation'; import { useTransition, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { setLoading } from '@/store/slices/uiSlice'; const redirectUser = (href: string) => { const router = useRouter(); const dispatch = useDispatch(); const [isPending, startTransition] = useTransition(); useEffect(() => { dispatch(setLoading(isPending)); }, [isPending, dispatch]); return () => { startTransition(() => { router.push(href); }); }; };
2. 监听路径变化手动重置状态
通过usePathname监听当前路径,当导航完成路径更新后,手动重置loading状态。需要注意排除初始渲染的情况。
import { useRouter, usePathname } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import { setLoading } from '@/store/slices/uiSlice'; const RedirectComponent = () => { const router = useRouter(); const pathname = usePathname(); const dispatch = useDispatch(); const [prevPath, setPrevPath] = useState(pathname); useEffect(() => { if (pathname !== prevPath) { dispatch(setLoading(false)); setPrevPath(pathname); } }, [pathname, prevPath, dispatch]); const handleRedirect = (href: string) => { dispatch(setLoading(true)); router.push(href); }; return <button onClick={() => handleRedirect('/dashboard')}>去控制台</button>; };
3. 用Suspense实现全局页面加载
如果只需要在页面切换时显示全局加载状态,直接用Suspense包裹页面组件,Next.js会自动在页面加载期间展示fallback内容。
// app/layout.tsx import { Suspense } from 'react'; import LoadingSpinner from '@/components/LoadingSpinner'; export default function RootLayout({ children }) { return ( <html lang="zh-CN"> <body> <Suspense fallback={<LoadingSpinner />}> {children} </Suspense> </body> </html> ); }
内容的提问来源于stack exchange,提问作者Shivam Sahil
相关产品推荐
相关产品推荐

