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,此时执行清理逻辑。
为什么你之前的写法有问题?
- 第一个
useEffect依赖filters:每次filters变化时,上一次的effect清理函数会被调用,这不符合你只在模态框关闭时执行的需求。 - 第二个空依赖的
useEffect:由于闭包特性,清理函数中的filters始终是初始渲染时的值,无法拿到最新的筛选条件。
内容的提问来源于stack exchange,提问作者Rasmus Knap
相关产品推荐
相关产品推荐

