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

Next.js路由切换加载效果实现:解决卸载组件状态更新警告及函数组件状态异常问题

解决Next.js路由切换加载效果的内存泄漏警告问题

这个问题我之前也遇到过,本质是路由事件监听器没有在组件卸载时清理——组件已经被卸载了,但路由事件触发时还试图更新它的状态,从而引发内存泄漏警告。咱们一步步来解决:

问题根源分析

你提供的两个版本代码都存在相同的核心问题:

  1. 类组件:componentWillUnmount中没有移除路由事件监听器,且用Router.onRouteChangeComplete = ...的赋值方式会覆盖全局回调,不是添加监听的正确姿势。
  2. 函数组件:直接在组件体中绑定事件,每次渲染都会重复添加监听器,且没有清理逻辑,导致组件卸载后监听器依然生效。

正确实现方案

方案1:类组件版本(修复后)

import Router from "next/router";
import { Component } from "react";
import Loader from "./Loader";

export default class Loading extends Component {
  constructor() {
    super();
    this.state = { loader: false };
    // 提前绑定监听函数并保存引用,方便后续移除
    this.handleRouteChangeStart = this.handleRouteChangeStart.bind(this);
    this.handleRouteReset = this.handleRouteReset.bind(this);
  }

  handleRouteChangeStart(url) {
    this.setState({ loader: true });
  }

  // 统一处理路由完成/失败的情况,避免加载器一直显示
  handleRouteReset(url) {
    this.setState({ loader: false });
  }

  componentDidMount() {
    // 使用events.on添加监听,而非赋值方式
    Router.events.on("routeChangeStart", this.handleRouteChangeStart);
    Router.events.on("routeChangeComplete", this.handleRouteReset);
    Router.events.on("routeChangeError", this.handleRouteReset);
  }

  componentWillUnmount() {
    // 组件卸载时必须移除所有添加的监听器
    Router.events.off("routeChangeStart", this.handleRouteChangeStart);
    Router.events.off("routeChangeComplete", this.handleRouteReset);
    Router.events.off("routeChangeError", this.handleRouteReset);
  }

  render() {
    return <Loader loading={this.state.loader} />;
  }
}

方案2:函数组件版本(修复后)

用useEffect钩子管理监听的生命周期,确保组件卸载时自动清理:

import Router from "next/router";
import { useState, useEffect } from "react";
import Loader from "./Loader";

export default function Loading() {
  const [loader, setLoader] = useState(false);

  useEffect(() => {
    // 定义监听函数
    const handleRouteChangeStart = (url) => {
      setLoader(true);
    };

    const handleRouteReset = (url) => {
      setLoader(false);
    };

    // 添加路由事件监听
    Router.events.on("routeChangeStart", handleRouteChangeStart);
    Router.events.on("routeChangeComplete", handleRouteReset);
    Router.events.on("routeChangeError", handleRouteReset);

    // 返回清理函数,组件卸载时自动执行
    return () => {
      Router.events.off("routeChangeStart", handleRouteChangeStart);
      Router.events.off("routeChangeComplete", handleRouteReset);
      Router.events.off("routeChangeError", handleRouteReset);
    };
  }, []); // 空依赖数组确保监听只绑定一次

  return <Loader loading={loader} />;
}

关键优化点说明

  • 必须清理监听器:在组件卸载时移除所有通过Router.events.on添加的监听器,避免组件卸载后还收到事件通知并调用setState。
  • 处理路由错误:添加routeChangeError的监听,防止路由切换失败时加载器一直处于显示状态。
  • 正确的监听方式:使用Router.events.on/off来添加/移除监听,而不是直接赋值Router.onRouteChangeComplete,后者会覆盖全局回调,影响其他组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 02:33:12