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

Next.js14中使用<Link>跳转自身页面时Loading.tsx不生效

问题

使用Next.js 14.2.7,根页面为服务器组件,通过Server Action获取票据,代码如下:

import { random } from "lodash";
import Link from "next/link";

const getTicket = () => new Promise<number>((r) => {
  const ret = random(1, 10000);
  setTimeout(() => r(ret), 2000)
})
export default async function Home() {

  const newTicket = await getTicket(); // Get a new ticket from server action

  return (
    <>
      <h1>Your new ticket is: {newTicket}</h1>
      <Link href={`/?q=${newTicket}`}>Get a new ticket</Link>
    </>
  );
}

Loading页面代码:

export default async function Loading() {
    return (
        <h1 className="loader">
            LOADING...
        </h1>
    )
}

点击浏览器刷新按钮时Loading页面可正常显示,但点击“Get a new ticket”链接时,页面会阻塞2秒直至新票据生成,Loading页面不生效。请问是否误解了Loading页面的用法?此场景下有哪些特殊配置或编码注意事项?

原因分析

你确实误解了Next.js中Loading.tsx的触发逻辑:

  • Loading.tsx是路由级加载组件,仅在初始页面刷新或切换到全新路由的服务器组件页面时触发。
  • 点击Link导航到同一个路由(仅查询参数变化)时,Next.js会复用当前页面的服务器组件实例,直接重新执行组件内的异步逻辑获取数据,不会触发路由级的Loading.tsx。

解决方法与注意事项

1. 改用Server Action触发数据更新(推荐)

将getTicket声明为Server Action,通过交互触发数据刷新,而非路由导航:

  • 第一步:将getTicket改为Server Action
// app/actions.ts
'use server';
import { random } from "lodash";

export async function getTicket() {
  return new Promise<number>((r) => {
    const ret = random(1, 10000);
    setTimeout(() => r(ret), 2000);
  });
}
  • 第二步:创建客户端组件作为交互入口,调用Server Action并刷新页面
// app/components/TicketButton.tsx
'use client';
import { useRouter } from 'next/navigation';
import { getTicket } from '../actions';

export default function TicketButton() {
  const router = useRouter();

  const handleClick = async () => {
    await getTicket();
    // 刷新当前路由,触发服务器组件重新获取数据
    router.refresh();
  };

  return (
    <button onClick={handleClick}>Get a new ticket</button>
  );
}
  • 第三步:在根服务器组件中引入该客户端组件
// app/page.tsx
import { getTicket } from './actions';
import TicketButton from './components/TicketButton';

export default async function Home() {
  const newTicket = await getTicket();

  return (
    <>
      <h1>Your new ticket is: {newTicket}</h1>
      <TicketButton />
    </>
  );
}
  • 注意:可在客户端组件中添加本地加载状态(比如点击按钮时显示"加载中..."),进一步优化用户体验。

2. 拆分页面为客户端组件+服务器组件

如果需要保留路由导航的方式,可将页面拆分为:

  • 服务器组件:负责获取并渲染票据数据
  • 客户端组件:负责处理导航交互,在跳转前显示本地加载状态

3. 正确理解Loading.tsx的适用场景

  • Loading.tsx仅用于跨路由切换时的加载状态展示,比如从/home跳转到/dashboard这类不同路由的场景。
  • 同路由内的数据更新,应该通过本地加载状态或Server Action + 路由刷新的方式处理,而非依赖Loading.tsx。

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:44:52