Next.js fallback:true时,提前访问未创建路径后无法生成对应新页面
问题背景
我使用getStaticPaths和getStaticProps生成博客页面,为了实现新增页面无需重启服务器即可访问,开启了fallback: true。相关代码如下:
getStaticPaths 代码
export async function getStaticPaths() { const paths = ...获取路径的代码... return { paths: paths, fallback: true }; }
getStaticProps 代码
export async function getStaticProps({ params }) { try { const post = await fetchPost(...某个ID...); return { props: { post }, revalidate: 60 }; } catch (e) { return { notFound: true }; } }
页面组件 fallback 处理代码
const SlugPage: NextPage<any> = props => { const theme = useTheme(); const router = useRouter(); if (router.isFallback) return ( <Loader colors={{ backgroundColor: theme.colors.earth.second, color: theme.colors.earth.fifth }} loading={true} /> ); ...页面其余内容... };
常规场景下,执行yarn build和yarn start后创建新页面/somenewslug,访问时能正常生成内容。但存在边缘问题:若在页面实际创建前就访问/somenewslug,此时getStaticProps返回notFound(当时逻辑正确),但后续创建该页面后,访问仍返回404,即使搭配revalidate也无效。
解决方案
1. 避免返回notFound: true,改用空Props传递
当获取不到文章时,不要返回notFound: true,而是返回props: { post: null }并保留revalidate配置。因为Next.js会缓存notFound的状态,视为永久404,不会再触发重新获取;而返回空Props配合revalidate,会让页面在指定时间后重新执行getStaticProps。
修改后的getStaticProps:
export async function getStaticProps({ params }) { try { const post = await fetchPost(...某个ID...); return { props: { post }, revalidate: 60 }; } catch (e) { // 不返回notFound,传递空post并保留revalidate return { props: { post: null }, revalidate: 60 }; } }
2. 在页面组件中处理空Post的情况
在页面里除了处理router.isFallback,还要判断post是否为null。此时可以显示加载状态,甚至添加定时刷新逻辑,确保文章创建后能及时获取到数据。
修改后的页面组件:
const SlugPage: NextPage<any> = props => { const theme = useTheme(); const router = useRouter(); if (router.isFallback) { return ( <Loader colors={{ backgroundColor: theme.colors.earth.second, color: theme.colors.earth.fifth }} loading={true} /> ); } // 处理文章尚未创建的情况 if (!props.post) { // 定时刷新页面,触发重新获取数据 useEffect(() => { const timer = setTimeout(() => { router.replace(router.asPath); }, 30000); // 30秒后刷新 return () => clearTimeout(timer); }, [router]); return ( <Loader colors={{ backgroundColor: theme.colors.earth.second, color: theme.colors.earth.fifth }} loading={true} /> ); } ...页面其余内容... };
3. 核心原理说明
Next.js中,当getStaticProps返回notFound: true时,这个状态会被持久化缓存,即使设置了revalidate也不会触发重新渲染。而返回包含空数据的Props并保留revalidate,Next.js会在每次请求或到达revalidate时间时,重新执行getStaticProps检查数据是否存在,从而解决提前访问导致的永久404问题。
内容的提问来源于stack exchange,提问作者Darkbound

