You need to enable JavaScript to run this app. 如何在使用getServerSideProps获取数据时展示加载指示器
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 18:18:02