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
相关产品推荐
相关产品推荐

