如何在使用getServerSideProps获取数据时展示加载指示器
解决方案
首先明确两种场景的处理逻辑:
1. 客户端路由跳转场景(软跳转,非硬刷新)
你已经实现的路由加载指示器可以直接覆盖这个场景,getServerSideProps 在客户端跳转时的执行周期会被Next.js的路由事件完整捕获:
- 跳转到使用
getServerSideProps的页面时,routeChangeStart事件会立即触发 - 服务端执行
getServerSideProps、返回数据的整个过程中,路由处于 pending 状态 - 直到
getServerSideProps执行完成、页面拿到数据准备渲染时,才会触发routeChangeComplete事件
你只需要在自定义_app.js里绑定这三个事件控制加载状态即可,示例代码:
import { useEffect, useState } from 'react' import { useRouter } from 'next/router' import Loading from '../components/Loading' // 你的自定义加载图标组件 export default function MyApp({ Component, pageProps }) { const router = useRouter() const [loading, setLoading] = useState(false) useEffect(() => { const handleStart = () => setLoading(true) const handleComplete = () => setLoading(false) const handleError = () => setLoading(false) router.events.on('routeChangeStart', handleStart) router.events.on('routeChangeComplete', handleComplete) router.events.on('routeChangeError', handleError) return () => { router.events.off('routeChangeStart', handleStart) router.events.off('routeChangeComplete', handleComplete) router.events.off('routeChangeError', handleError) } }, [router]) return <> {loading && <Loading />} <Component {...pageProps} /> </> }
2. 首次访问/硬刷新场景
这种场景下getServerSideProps执行时,浏览器还在等待服务端返回HTML,客户端还没有加载任何JS代码,没法用React状态控制加载。你可以通过自定义_document.js注入内联的加载样式和元素,在页面 hydration 完成前展示加载状态:
import Document, { Html, Head, Main, NextScript } from 'next/document' class MyDocument extends Document { render() { return ( <Html> <Head> <style>{` #initial-loading { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; background: #fff; z-index: 9999; } /* 自定义加载动画样式 */ .spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `}</style> </Head> <body> {/* 首屏加载元素 */} <div id="initial-loading"> <div class="spinner"></div> </div> <Main /> <NextScript /> {/* 加载完成后隐藏首屏加载元素 */} <script>{` window.addEventListener('load', () => { document.getElementById('initial-loading').style.display = 'none' }) `}</script> </body> </Html> ) } } export default MyDocument
补充说明
如果你觉得两种方案分开处理太麻烦,也可以直接把数据获取逻辑从getServerSideProps移到客户端,用SWR或者React Query这类请求库处理,自带加载、缓存、重试能力,加载状态可以完全用前端逻辑控制,不用区分跳转场景。
内容的提问来源于stack exchange,提问作者Paras Buda
相关产品推荐
相关产品推荐

