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

在Tauri+React中如何正确在组件卸载时清理事件监听?

问题原因分析

React StrictMode 在开发环境会双重执行组件的挂载/卸载流程(先挂载→立即卸载→再次挂载),你的代码里registerListener是异步函数,第一次触发卸载时,unsubscribe还没完成赋值,导致第一次注册的监听完全没被清理;第二次挂载后又新增了一个监听,最终只有第二次的监听能被正常注销,残留的第一次监听就会出现「仅能完成一次注销」的异常。

修复方案

用useRef跟踪注销函数和组件挂载状态,确保异步流程中也能正确清理副作用:

import { useEffect, useRef } from 'react';

// ...

useEffect(() => {
  const unsubscribeRef = useRef<(() => void) | null>(null);
  const isMounted = useRef(true);

  const registerListener = async () => {
    // 注册新监听前,先清理可能存在的旧监听
    if (unsubscribeRef.current) {
      unsubscribeRef.current();
      unsubscribeRef.current = null;
    }

    const unsubscribe = await listen<string>('new_number', (event) => {
      console.log('Received event:', event.payload);
      // 组件已卸载时,跳过状态更新
      if (isMounted.current) {
        setNumber(event.payload);
      }
    });

    // 组件仍挂载时才保存注销函数,否则直接注销
    if (isMounted.current) {
      unsubscribeRef.current = unsubscribe;
    } else {
      unsubscribe();
    }
  };

  registerListener();

  return () => {
    // 标记组件已卸载,阻断后续异步操作
    isMounted.current = false;
    // 执行注销并清空ref
    if (unsubscribeRef.current) {
      unsubscribeRef.current();
      unsubscribeRef.current = null;
    }
  };
}, []);
关键改动说明
  • 用unsubscribeRef存储注销函数:避免异步赋值时丢失引用,确保清理函数能拿到最新的注销方法。
  • 增加isMounted标志:防止组件卸载后还执行setNumber或赋值注销函数,避免内存泄漏。
  • 注册前清理旧监听:应对StrictMode的双重挂载,避免重复注册多个监听。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 18:49:51