Next.js中useRouter跳转时getStaticProps的Fallback页面不显示问题
Next.js中useRouter跳转时不显示Fallback加载页的原因与解决办法
问题原因
直接输入URL和使用useRouter跳转的核心差异在于页面加载时机与组件挂载逻辑:
- 直接输入URL时,浏览器会向服务器请求页面,服务器执行
getStaticProps后返回页面内容。如果数据未加载完成,返回空props,客户端渲染NewPage时会触发内部的LoadingPage。 - 使用
useRouter跳转时,Next.js会在客户端后台预获取目标页面的组件和getStaticProps结果,这个过程中原页面会持续展示,直到预获取完成才会切换到目标页。此时NewPage的props已经加载完成,自然不会触发内部的LoadingPage。
你的LoadingPage依赖目标页的props是否存在,但跳转过程中目标页组件并未挂载,所以用户看不到加载状态。
解决方案
方案一:全局路由监听显示加载状态
在_app.js中监听路由变化事件,全局显示加载组件,覆盖所有跳转场景:
import { useRouter } from 'next/router'; import { useState, useEffect } from 'react'; import LoadingPage from '../components/LoadingPage'; function MyApp({ Component, pageProps }) { const router = useRouter(); const [isLoading, setIsLoading] = useState(false); useEffect(() => { const startLoading = () => setIsLoading(true); const stopLoading = () => setIsLoading(false); router.events.on('routeChangeStart', startLoading); router.events.on('routeChangeComplete', stopLoading); router.events.on('routeChangeError', stopLoading); return () => { router.events.off('routeChangeStart', startLoading); router.events.off('routeChangeComplete', stopLoading); router.events.off('routeChangeError', stopLoading); }; }, [router]); return ( <> {isLoading && <LoadingPage />} <Component {...pageProps} /> </> ); } export default MyApp;
方案二:跳转发起页手动控制加载状态
在触发跳转的页面中,点击按钮后立即显示加载组件,直到跳转完成:
import { useRouter } from 'next/router'; import { useState } from 'react'; import LoadingPage from '../components/LoadingPage'; function OldPage(props) { const router = useRouter(); const [isRedirecting, setIsRedirecting] = useState(false); async function redirect(path) { setIsRedirecting(true); try { await router.push({ pathname: path, query: { xyz } }); } finally { setIsRedirecting(false); } } return ( <> {isRedirecting && <LoadingPage />} <button onClick={() => redirect('/new-page')}>Redirect</button> </> ); }
方案三:动态路由下启用fallback模式(适用于动态路由页面)
如果NewPage是动态路由(如[id].js),可通过getStaticPaths配置fallback: true,让Next.js先返回加载页,后台生成静态内容后再切换:
// NewPage.js import { useRouter } from 'next/router'; import LoadingPage from '../components/LoadingPage'; export async function getStaticPaths() { return { paths: [], // 空数组表示所有路径都动态生成 fallback: true }; } export async function getStaticProps(context) { const data = await someLoadingFunction(context.params.id); if (!data) return { notFound: true }; return { props: { data }, revalidate: 60 // 可选,增量静态再生 }; } function NewPage(props) { const router = useRouter(); // 路由未准备好时显示加载页 if (!router.isReady) { return <LoadingPage />; } if (!props.data) { return <div>数据不存在</div>; } return ( // 页面内容 ); }
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

