Next.js 的 loading.js 为什么有时候不生效?

UX德丽 阅读 4

我在用 Next.js 13 的 App Router,按照文档在页面文件夹里加了 loading.js,但有些路由切换的时候 Loading 组件根本不显示,是哪里没配对吗?

比如我从首页点进用户详情页,明明网络请求要等一两秒,但页面直接卡住,loading UI 完全没出来。我试过把 loading.js 放在和 page.js 同级目录,也确认导出的是默认组件:

export default function Loading() {
  return <p>Loading...</p>;
}

是不是因为用了 useEffect 做数据获取?还是说某些跳转方式会绕过 Loading 机制?

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
码农倩倩
这个问题我之前也踩过坑,Next.js 的 loading.js 机制确实容易让人误解。让我一步步帮你排查。

第一步,先搞清楚 loading.js 的触发条件。

loading.js 本质上是 React Suspense 的语法糖,它只有在服务端组件进行异步数据获取时才会生效。Next.js 会在服务端等待数据请求完成,期间把 loading.js 的内容作为 fallback 显示给用户。

你说用了 useEffect 做数据获取,这大概率就是问题所在。useEffect 是在客户端执行的,这时候页面已经加载完了,loading.js 早就完成使命了,自然看不到任何效果。

第二步,检查你的数据获取方式。

看看你的页面组件是不是这样写的:

// 这种写法 loading.js 永远不会生效
'use client'; // 客户端组件标记

import { useState, useEffect } from 'react';

export default function UserPage() {
const [user, setUser] = useState(null);

useEffect(() => {
fetch('/api/user').then(res => res.json()).then(setUser);
}, []);

if (!user) return

Loading...

; // 这是客户端渲染的

return
{user.name}
;
}


这种写法的问题在于,页面会先完整渲染一个空壳发给客户端,然后客户端才开始请求数据。loading.js 在服务端阶段就结束了,根本等不到你的 useEffect 执行。

第三步,改成服务端组件的方式。

把数据获取逻辑移到服务端,让 Next.js 在服务端等待数据:

// page.js - 不要加 'use client'
async function getUser() {
const res = await fetch('https://api.example.com/user', {
// 禁用缓存,确保每次都能看到 loading 效果
cache: 'no-store'
});
return res.json();
}

export default async function UserPage() {
// 直接在组件里 await,Next.js 会自动处理
const user = await getUser();

return (

{user.name}


{user.email}



);
}


这样写的话,Next.js 在服务端执行 getUser() 期间,会自动显示 loading.js 的内容。

第四步,确认你的目录结构。

目录结构要这样放才对:

app/
├── page.js // 首页
├── loading.js // 首页的 loading(其实首页一般用不上)
└── user/
├── page.js // 用户详情页
└── loading.js // 用户详情页的 loading,必须和 page.js 同级


loading.js 必须和对应的 page.js 放在同一个文件夹里,不是放在 page.js 的上一层。

第五步,还有一个容易被忽略的点。

如果你的页面已经被静态生成了,或者有缓存,那 loading 也不会显示,因为根本没有"等待"这个过程。可以在 fetch 里加 cache: 'no-store' 或者在页面组件里加 export const dynamic = 'force-dynamic' 来强制动态渲染:

// 强制动态渲染,每次请求都会触发 loading
export const dynamic = 'force-dynamic';

export default async function UserPage() {
// ...
}


最后总结一下,你的问题大概率就是客户端组件 + useEffect 这个组合导致的。改成服务端组件直接 async/await 获取数据,loading.js 就能正常工作了。

如果非要用客户端组件,那就得自己用 useState 管理加载状态,loading.js 帮不了你。这也是很多从 React SPA 转过来的开发者容易混淆的地方,毕竟习惯了自己管理 loading 状态。
点赞
2026-03-03 01:00