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

React Navigation v4中监听模态框关闭事件的实现咨询

解决React Navigation v4模态框关闭事件监听的问题

针对你的需求,我有两个可行的方案,其中第二个方案更简洁直接,推荐优先尝试:

方案一:使用useRef保存最新filters,在组件卸载时执行清理

你的核心问题之一是组件卸载时无法获取最新的filters值,这是闭包导致的——空依赖数组的useEffect里的filters会一直是初始渲染时的值。我们可以用useRef来实时保存最新的filters,这样卸载时就能拿到正确的值:

import { useRef, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { taskFilters } from './your-redux-selectors'; // 替换成你的实际选择器路径
import { cleanUpAndFetch } from './your-redux-actions'; // 替换成你的实际action路径

const MyModal = ({ navigation }) => {
  const filters = useSelector(taskFilters);
  const dispatch = useDispatch();
  // 用ref保存最新的filters值
  const latestFilters = useRef(filters);

  // 每次filters更新时,同步更新ref
  useEffect(() => {
    latestFilters.current = filters;
  }, [filters]);

  // 组件卸载时触发(仅当MyModal真正关闭回到Main时才会卸载)
  useEffect(() => {
    return () => {
      // 使用ref中保存的最新filters
      dispatch(cleanUpAndFetch(latestFilters.current));
    };
  }, [dispatch]);

  // ... 你的模态框UI代码

  return (
    // 模态框内容
  );
};

为什么这个方案有效?

  • React Navigation v4的栈导航中,当你从MyModal打开ChildModal时,MyModal仍然保留在导航栈中,组件不会卸载,所以这个清理函数不会触发。
  • 只有当你关闭MyModal(回到Main页面,无论是下滑关闭还是调用navigation.goBack()),MyModal会被弹出栈并卸载,此时清理函数执行,且通过latestFilters.current拿到的是最新的筛选条件。

方案二:监听导航状态变化,判断模态框是否被移除

如果你需要更精确地监听导航栈的变化(比如担心组件卸载逻辑受导航配置影响),可以通过监听导航的didBlur事件,结合导航栈的路由列表来判断MyModal是否真正被关闭:

import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigationState } from 'react-navigation';
import { taskFilters } from './your-redux-selectors';
import { cleanUpAndFetch } from './your-redux-actions';

const MyModal = ({ navigation }) => {
  const filters = useSelector(taskFilters);
  const dispatch = useDispatch();
  // 获取当前导航栈的状态
  const navigationState = useNavigationState(state => state);

  useEffect(() => {
    const handleDidBlur = () => {
      // 检查当前导航栈中是否还存在MyModal的路由
      const isMyModalInStack = navigationState.routes.some(route => route.routeName === 'MyModal');
      if (!isMyModalInStack) {
        // MyModal已被移出栈,执行清理逻辑
        dispatch(cleanUpAndFetch(filters));
      }
    };

    // 监听didBlur事件
    const unsubscribe = navigation.addListener('didBlur', handleDidBlur);
    // 组件卸载时取消监听
    return unsubscribe;
  }, [navigation, navigationState, filters, dispatch]);

  // ... 你的模态框UI代码

  return (
    // 模态框内容
  );
};

这个方案的逻辑:

  • 当从MyModal打开ChildModal时,MyModal的didBlur事件会触发,但此时导航栈的routes数组包含Main、MyModal、ChildModal,isMyModalInStack为true,不会执行清理。
  • 当关闭MyModal回到Main时,routes数组只剩下Main,isMyModalInStack为false,此时执行清理逻辑。

为什么你之前的写法有问题?

  1. 第一个useEffect依赖filters:每次filters变化时,上一次的effect清理函数会被调用,这不符合你只在模态框关闭时执行的需求。
  2. 第二个空依赖的useEffect:由于闭包特性,清理函数中的filters始终是初始渲染时的值,无法拿到最新的筛选条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:02:44