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

Next.js Link触发Loading initial props cancelled错误,求优雅解决方案

解决Next.js重复点击Link触发Loading initial props cancelled错误

问题原因

快速重复点击同一Next.js Link时,新的路由跳转请求会中断正在进行的页面初始props加载流程,从而抛出Error: Loading initial props cancelled错误。你当前使用useState控制加载状态的方案存在缺陷:useState的更新是异步的,快速点击时无法及时拦截重复请求。

优雅解决方案

方案一:使用useRef维护跳转状态(快速实现)

利用useRef的同步更新特性,结合Next.js Router的事件监听,精准控制跳转状态:

// navbar.ts
import { useRouter } from 'next/router';
import { useRef, useEffect } from 'react';
import Link from 'next/link';

const Navbar = () => {
  const router = useRouter();
  // 存储当前是否正在路由跳转的状态
  const isNavigating = useRef(false);

  useEffect(() => {
    // 路由开始跳转时标记状态
    const handleRouteStart = () => {
      isNavigating.current = true;
    };
    // 路由完成/出错时重置状态
    const handleRouteEnd = () => {
      isNavigating.current = false;
    };

    router.events.on('routeChangeStart', handleRouteStart);
    router.events.on('routeChangeComplete', handleRouteEnd);
    router.events.on('routeChangeError', handleRouteEnd);

    // 组件卸载时移除事件监听
    return () => {
      router.events.off('routeChangeStart', handleRouteStart);
      router.events.off('routeChangeComplete', handleRouteEnd);
      router.events.off('routeChangeError', handleRouteEnd);
    };
  }, [router]);

  const handleLinkClick = (e: React.MouseEvent, targetPath: string) => {
    // 正在跳转或已在目标页面时,阻止默认跳转行为
    if (isNavigating.current || router.asPath === targetPath) {
      e.preventDefault();
      return;
    }
  };

  return (
    <nav>
      <Link 
        href="/example" 
        onClick={(e) => handleLinkClick(e, '/example')}
      >
        Go to Example
      </Link>
      {/* 其他Link复用相同逻辑 */}
    </nav>
  );
};

export default Navbar;

方案二:封装自定义Link组件(高复用性)

将重复点击拦截逻辑封装成通用组件,项目中所有Link统一替换,避免重复代码:

// components/CustomLink.tsx
import { useRouter } from 'next/router';
import { useRef, useEffect } from 'react';
import Link, { LinkProps } from 'next/link';

const CustomLink = ({ href, children, ...props }: LinkProps) => {
  const router = useRouter();
  const isNavigating = useRef(false);

  useEffect(() => {
    const handleStart = () => (isNavigating.current = true);
    const handleEnd = () => (isNavigating.current = false);

    router.events.on('routeChangeStart', handleStart);
    router.events.on('routeChangeComplete', handleEnd);
    router.events.on('routeChangeError', handleEnd);

    return () => {
      router.events.off('routeChangeStart', handleStart);
      router.events.off('routeChangeComplete', handleEnd);
      router.events.off('routeChangeError', handleEnd);
    };
  }, [router]);

  const handleClick = (e: React.MouseEvent) => {
    if (isNavigating.current || router.asPath === href) {
      e.preventDefault();
    }
  };

  return (
    <Link href={href} onClick={handleClick} {...props}>
      {children}
    </Link>
  );
};

export default CustomLink;

使用时直接替换原生Link:

// navbar.ts
import CustomLink from '@/components/CustomLink';

const Navbar = () => {
  return (
    <nav>
      <CustomLink href="/example">Go to Example</CustomLink>
      {/* 其他页面链接直接使用CustomLink */}
    </nav>
  );
};

补充说明

该问题在Next.js 12及13版本中均存在,官方暂未完全修复上述场景。上述方案通过拦截重复的跳转请求,从根源上避免了加载流程被中断的情况,同时保证了用户操作的流畅性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:22:19