You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NextJS页面首次加载(非路由切换)时显示预加载器?

在Next.js中实现页面首次加载时的加载器

核心思路

页面首次加载(刷新、新开标签页访问)时,Next.js Router不会触发路由切换事件,所以得从页面初始化阶段入手,通过React状态管理结合页面加载/数据加载的时机来控制加载器的显示与隐藏。

Pages Router 实现方案

1. 全局_app.jsx/tsx 统一处理

在全局入口文件中维护加载状态,监听页面资源加载完成事件:

// pages/_app.jsx
import { useState, useEffect } from 'react';
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const handlePageLoad = () => setIsLoading(false);

    // 若页面已加载完成,直接关闭加载器
    if (document.readyState === 'complete') {
      handlePageLoad();
    } else {
      window.addEventListener('load', handlePageLoad);
      return () => window.removeEventListener('load', handlePageLoad);
    }
  }, []);

  if (isLoading) {
    // 自定义加载器组件,可替换为动画效果
    return (
      <div style={{
        position: 'fixed',
        inset: 0,
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        background: '#fff'
      }}>
        <div>加载中...</div>
      </div>
    );
  }

  return <Component {...pageProps} />;
}

export default MyApp;

2. 结合数据加载时机控制

如果页面依赖服务端数据,可在页面组件中结合数据加载完成状态关闭加载器:

// pages/index.jsx
import { useState, useEffect } from 'react';

export async function getServerSideProps() {
  // 模拟服务端数据请求延迟
  await new Promise(resolve => setTimeout(resolve, 1200));
  return { props: { content: '首页内容' } };
}

export default function Home({ content }) {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 数据就绪后关闭加载器
    setIsLoading(false);
  }, [content]);

  if (isLoading) {
    return <div className="loader">加载中...</div>;
  }

  return <div>{content}</div>;
}

App Router 实现方案

1. Root Layout 全局处理

在根布局中添加全局加载器,覆盖首次加载场景:

// app/layout.jsx
import { useState, useEffect } from 'react';
import './globals.css';

export default function RootLayout({ children }) {
  const [isFirstLoad, setIsFirstLoad] = useState(true);

  useEffect(() => {
    const checkLoadStatus = () => {
      if (document.readyState === 'complete') {
        setIsFirstLoad(false);
      }
    };

    checkLoadStatus();
    window.addEventListener('load', checkLoadStatus);
    return () => window.removeEventListener('load', checkLoadStatus);
  }, []);

  return (
    <html lang="zh-CN">
      <body>
        {isFirstLoad ? (
          <div className="global-loader">
            <span>正在初始化页面...</span>
          </div>
        ) : (
          children
        )}
      </body>
    </html>
  );
}

2. 单个页面独立处理

仅需特定页面显示首次加载器时,直接在对应page.jsx中实现:

// app/page.jsx
import { useState, useEffect } from 'react';

export default function Home() {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 可替换为数据加载完成的回调,而非固定延迟
    const timer = setTimeout(() => setIsLoading(false), 600);
    return () => clearTimeout(timer);
  }, []);

  if (isLoading) {
    return <div className="page-loader">加载中...</div>;
  }

  return <main>首页内容</main>;
}

优化建议

  • 避免固定延迟:优先用window.load事件(等待所有资源加载完成)或数据请求的完成状态来切换加载器,减少不必要的等待。
  • 平滑过渡效果:给加载器添加CSS过渡,提升体验:
.global-loader {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #fff;
  transition: opacity 0.3s ease;
}

.global-loader.hidden {
  opacity: 0;
  pointer-events: none;
}
  • 结合Suspense:App Router中可搭配React Suspense处理组件级加载,但全局首次加载的加载器仍需依赖状态管理。

内容的提问来源于stack exchange,提问作者Grosu Cristi-Alexandru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 16:40:22