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

Next.js 13加载用户数据时避免页面切换闪烁,如何实现加载屏?

解决Next.js 13页面加载闪烁问题,添加加载屏优化

你当前页面出现逐个显示的问题,核心原因是user、premiumStatus这些状态是异步加载的,初始渲染时它们的默认值(比如null/false)会触发条件渲染,等异步数据返回后又切换到正确页面,导致视觉闪烁。要解决这个问题,关键是先等状态数据加载完成,再渲染目标页面,加载过程中显示统一的加载屏。

步骤1:在UserContext中添加加载状态

首先需要在你的用户上下文里新增一个loading状态,标记用户数据是否加载完成:

// userContext.js 示例代码
import { createContext, useContext, useState, useEffect } from 'react';

const UserContext = createContext();

export function UserProvider({ children }) {
  const [user, setUser] = useState(null);
  const [premiumStatus, setPremiumStatus] = useState(false);
  const [unlock, setUnlock] = useState(false);
  const [loading, setLoading] = useState(true); // 新增加载状态

  useEffect(() => {
    // 替换成你实际的用户数据获取逻辑(比如从API/localStorage读取)
    const fetchUserData = async () => {
      try {
        const storedUser = localStorage.getItem('user');
        const storedPremium = localStorage.getItem('premiumStatus');
        
        if (storedUser) {
          setUser(JSON.parse(storedUser));
          setPremiumStatus(storedPremium === 'true');
        }
      } catch (err) {
        console.error('加载用户数据失败:', err);
      } finally {
        setLoading(false); // 数据加载完成,关闭加载状态
      }
    };

    fetchUserData();
  }, []);

  // 保留你原有的logoutUser、unlock相关方法
  const logoutUser = () => {
    // 你的登出逻辑
  };

  return (
    <UserContext.Provider value={{ user, premiumStatus, unlock, logoutUser, loading }}>
      {children}
    </UserContext.Provider>
  );
}

export function useUserContext() {
  return useContext(UserContext);
}

步骤2:修改HomePage组件,添加加载屏逻辑

在首页组件中,先判断加载状态,加载中时显示加载屏;加载完成后再处理页面渲染和路由跳转:

import { useRouter } from "next/navigation";
import { useEffect } from "react";
import Login from "../../components/auth/Login";
import Particle from "../../components/Particle";
import Plans from "../../components/stripe/Plans";
import { useUserContext } from "./../context/userContext";
import { ArrowLeft } from "phosphor-react";

// 自定义加载屏,可根据需求修改样式
function LoadingScreen() {
  return (
    <div className="flex h-screen items-center justify-center bg-gray-100">
      <div className="flex flex-col items-center gap-4">
        <div className="w-12 h-12 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
        <span className="text-lg text-gray-700">加载中...</span>
      </div>
    </div>
  );
}

function HomePage() {
  const router = useRouter();
  const { user, premiumStatus, unlock, logoutUser, loading } = useUserContext();

  // 用useEffect处理路由跳转,避免在渲染阶段执行副作用
  useEffect(() => {
    if (!loading && user && premiumStatus) {
      router.replace("../dashboard");
    }
  }, [loading, user, premiumStatus, router]);

  // 加载中时直接显示加载屏
  if (loading) {
    return <LoadingScreen />;
  }

  // 加载完成后渲染对应页面
  return (
    <>
      {!user ? (
        <Login />
      ) : (
        <div>
          {!premiumStatus ? (
            <div className="flex h-screen justify-center">
              <Particle />
              <button
                onClick={logoutUser}
                title="Logout"
                className="fixed top-0 left-0 text-white p-4"
              >
                <ArrowLeft className="w-10 h-10" />
              </button>
              {unlock && <Plans />}
            </div>
          ) : null}
        </div>
      )}
    </>
  );
}

export default HomePage;

关键注意点

  • 不要在渲染逻辑中直接调用router.replace:这会触发React严格模式警告,改用useEffect可以确保状态稳定后再执行跳转。
  • 加载屏可自定义:你可以替换LoadingScreen组件的内容,比如添加品牌logo、更复杂的动画效果。
  • 确保loading状态正确切换:必须在异步数据加载完成(包括异常情况)后,才将loading设为false,否则仍会出现页面闪烁。

内容的提问来源于stack exchange,提问作者Marcos Lo Vetro Coca Filho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:12:36