深度链接后重置导航状态:解决应用重启跳转异常问题
如何移除深度链接留下的默认路由状态?
应用通过深度链接跳转后,该深度链接指定的路由会成为默认首页。此后每次更新应用(Android模拟器上自动重载),应用都会跳转至该深度链接路由,而非预期的首页。需要将此路由从导航状态中移除,确保重载后默认进入首页。
场景演示
- 执行命令:
adb shell am start -W -a android.intent.action.VIEW -d "casualjob://InvitedEmployee" com.casualjob - 应用被触发并跳转至
InvitedEmployee路由 - 用户点击首页链接跳转至首页
- 更新应用代码
- 应用自动重载以反映代码变更
- 应用启动后进入
InvitedEmployee路由,而非首页,期望启动后跳转至首页!
深度链接配置
const config = { screens: { SingleStack: { initialRouteName: "InitialScreen", screens: { EmployerActionVacancyScreen: "EmployerVacancyAction/:itemID/:opType/:itemStatus?", ListShiftEmployeeInviteScreen: "InvitedEmployee", InitialScreen: "*", }, }, } };
栈定义
const SingleStack = () => { const MyStack = createNativeStackNavigator(); return ( <MyStack.Navigator screenOptions={defaultScreenOptions}> <MyStack.Screen name="InitialScreen" component={InitialScreen} options={{ title: "Home" }}/> <MyStack.Screen name="ListShiftEmployeeInviteScreen" component={ListShiftEmployeeInviteScreen} options={{ title: "Shifts List", }}/> </MyStack.Navigator> ); };
尝试过的无效方案
方案1(抛出错误)
错误信息:The action 'RESET' with payload {"index":0,"routes":[{"name":"initialScreen"}]} was not handled by any navigator. This is a development-only warning and won't be shown in production.
const isFocused = useIsFocused(); useEffect( () => { async function _fetchData() { props.navigation.reset({ index: 0, routes: [{ name: "initialScreen" }], // this is the home screen }); } if (isFocused) { _fetchData(); } }, [isFocused, ]);
方案2(无任何效果)
应用代码更新重载后,深度链接路由重新出现在导航状态中。
const isFocused = useIsFocused(); useEffect( () => { async function _fetchData() { props.navigation.dispatch(state => { if (!state?.routes || state?.routes < 2) { return; } const routes = state.routes.filter( (item, index) => { if (item.name === "ListShiftEmployeeInviteScreen") { // This is the route (screen) that the deep link leads to return false; } return true; }); if (routes?.length > 0) { return CommonActions.reset({ ...state, routes, index: routes.length - 1, }); } return; }); } if (isFocused) { _fetchData(); } }, [isFocused, ]);
解决方案
1. 修复方案1的路由名大小写问题
方案1报错的核心原因是路由名大小写不匹配:代码中写的是小写的initialScreen,但栈定义里的首页路由名是大写开头的InitialScreen。修改后即可生效:
const isFocused = useIsFocused(); useEffect( () => { async function _fetchData() { props.navigation.reset({ index: 0, routes: [{ name: "InitialScreen" }], // 修正为正确的路由名 }); } if (isFocused) { _fetchData(); } }, [isFocused, ]);
2. 在根导航容器层面统一处理
如果子组件的useEffect执行时机不稳定,可以在根组件中直接监听导航状态,在应用启动(包括热重载)时重置路由:
import { useNavigationContainerRef, CommonActions } from '@react-navigation/native'; const App = () => { const navigationRef = useNavigationContainerRef(); useEffect(() => { const currentState = navigationRef.getCurrentState(); // 检查当前栈的第一个路由是否是深度链接指向的路由 if (currentState?.routes[0]?.name === 'ListShiftEmployeeInviteScreen') { navigationRef.dispatch( CommonActions.reset({ index: 0, routes: [{ name: 'InitialScreen' }], }) ); } }, []); // 空依赖确保只在挂载/热重载时执行一次 return ( <NavigationContainer ref={navigationRef} linking={config}> <SingleStack /> </NavigationContainer> ); };
3. 修改深度链接的处理逻辑(可选)
如果希望只有冷启动时处理深度链接,热重载时忽略,可以在链接配置中添加enabled条件,判断是否为热重载状态(可结合React Native的__DEV__标识和原生模块实现),或者在处理深度链接时记录状态,避免重复触发。
内容的提问来源于stack exchange,提问作者Bilal Abdeen
相关产品推荐
相关产品推荐

