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

Next.js路由事件异常:加载页面无法自动消失问题排查

解决Next.js加载提示无法自动消失的问题

在Next.js中实现页面加载提示功能时,用户导航到新页面会显示加载提示,但偶尔会出现加载提示一直停留无法消失的情况。推测是状态未正确更新或路由加载后未正确检查路径导致,尝试在useEffect依赖数组中加入router、router.asPath和router.events后问题依旧,需要解决加载提示在页面加载完成后自动消失的问题。

原代码示例

Loading组件:

import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/router';

export default function Loading() {
    const router = useRouter()
    const [loading, setLoading] = useState(false)

  useEffect(() => {
    const hanldeChangeStart = (url) => {
      url !== router.asPath && setLoading(true)
    }
    const hanldeChangeComplete = (url) => {
      url === router.asPath && setLoading(false)
    }
  
    router.events.on('routeChangeStart', hanldeChangeStart)
    router.events.on('routeChangeComplete', hanldeChangeComplete)
    router.events.on('routeChangeError', hanldeChangeComplete)
    
    return () => {
      router.events.off('routeChangeStart', hanldeChangeStart)
      router.events.off('routeChangeComplete', hanldeChangeComplete)
      router.events.off('routeChangeError', hanldeChangeComplete)
    }
  })

  if(loading){
    return (
        <div className='vh-100 vw-100 text-center'>
        <h1>Loading...</h1>
        <p>{loading ? 'loading' : 'notloading'}</p>
        </div>
    )
  } 
}

_app.js:

import Loading from '@/components/Loading';

export default function App({ Component, pageProps }) {
  return (
    <>
      <Loading />
      <Component {...pageProps} />
    </>
  )
}

问题分析与修复方案

原代码存在三个核心问题:

  1. useEffect缺少依赖数组,会导致组件每次渲染时重复绑定路由事件,引发状态更新混乱
  2. routeChangeComplete事件中通过url === router.asPath判断存在逻辑漏洞——路由完成后router.asPath已更新为目标URL,该判断可能失效
  3. Loading组件在loading为false时未返回任何节点,不符合React组件的渲染规范

修复后的Loading组件代码:

import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/router';

export default function Loading() {
    const router = useRouter()
    const [loading, setLoading] = useState(false)

  useEffect(() => {
    const handleRouteChangeStart = () => {
      setLoading(true)
    }
    const handleRouteChangeEnd = () => {
      setLoading(false)
    }
  
    router.events.on('routeChangeStart', handleRouteChangeStart)
    router.events.on('routeChangeComplete', handleRouteChangeEnd)
    router.events.on('routeChangeError', handleRouteChangeEnd)
    
    return () => {
      router.events.off('routeChangeStart', handleRouteChangeStart)
      router.events.off('routeChangeComplete', handleRouteChangeEnd)
      router.events.off('routeChangeError', handleRouteChangeEnd)
    }
  }, []) // 空依赖数组,确保仅在组件挂载时绑定一次事件

  return loading ? (
    <div className='vh-100 vw-100 text-center'>
      <h1>Loading...</h1>
      <p>loading</p>
    </div>
  ) : null; // loading为false时返回null,避免无意义渲染
}

修复说明

  • 空依赖数组:确保useEffect仅在组件挂载时执行一次,避免重复绑定路由事件导致的状态异常
  • 简化事件逻辑:去掉冗余的URL判断,路由开始时直接设loading为true,路由完成/出错时直接设为false,逻辑更可靠
  • 统一返回值:组件始终返回一个合法节点(加载提示或null),符合React组件渲染要求

如果需要处理同路由参数变化的场景(如动态路由/post/[id]),可在useEffect的依赖数组中加入router.asPath,并添加对应逻辑:

useEffect(() => {
  // 原有事件绑定逻辑...
  
  // 处理同路由参数变化
  setLoading(false)
}, [router.asPath])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:00:22