React Navigation中深度链接跳转SignedIn栈页面的参数传递问题
我太懂你现在的困扰了——默认signedIn是false,深度链接一进来先匹配到SignedOut栈,但APP自动登录后切到SignedIn栈,之前的深度链接参数直接就丢了,折腾半天确实头大。咱们一步步拆解问题,搞定它:
问题到底出在哪?
核心原因是登录状态是异步获取的,但导航容器一开始就根据默认的signedIn: false渲染了SignedOut栈。深度链接先匹配到这个栈的路由,可等登录完成切换到SignedIn栈时,之前的路由参数根本没机会传递过去,相当于导航状态被重置了。
解决方案分步走
1. 先等登录状态确定,再渲染导航栈
别着急一开始就渲染SignedOut或者SignedIn栈,先等isSignedIn()的异步结果回来。这样导航容器能在明确用户是否登录后,再正确处理深度链接的匹配逻辑,不会一开始就走错分支。
修改代码如下:
// 新增一个加载状态,标记登录状态是否已确定 const [isLoadingAuth, setIsLoadingAuth] = useState(true); useEffect(() => { async function checkAuth() { const isUserSignedIn = await isSignedIn(); setSignedIn(isUserSignedIn); setIsLoadingAuth(false); // 登录状态确定后,结束加载 } checkAuth(); }, [auth]); // 渲染部分调整 return ( <AuthContext.Provider value={a}> <UserContext.Provider value={u}> <WalletContext.Provider value={w}> <NavigationContainer linking={linking} ref={navigationRef} fallback={<Text>Loading...</Text>} > <Stack.Navigator> {isLoadingAuth ? ( {/* 登录状态未确定时,显示加载页 */} <Stack.Screen name="AuthLoading" component={() => <Text>Checking your login status...</Text>} options={{ headerShown: false }} /> ) : !signedIn ? ( <Stack.Screen name="SignedOut" component={SignedOutScreens} options={{ headerShown: false }} /> ) : ( <Stack.Screen name="SignedIn" component={SignedInScreens} options={{ headerShown: false }} /> )} </Stack.Navigator> </NavigationContainer> </WalletContext.Provider> </UserContext.Provider> </AuthContext.Provider> );
2. 给SignedIn栈也配置深度链接路径
既然你要在登录后跳转到SignedIn栈里的AddNewUser页面,就得把adduser的路径也加到SignedIn的路由配置里,让导航容器知道登录后该匹配哪个页面:
const linking = { prefixes: ["myapp://"], config: { screens: { SignedOut: { screens: { AddConnection: { path: "adduser/:address/:name/:command?", parse: { address: (address) => `${address}`, command: (command) => `${command}`, name: (name) => `${name}`, }, }, }, }, // 新增SignedIn栈的深度链接配置 SignedIn: { screens: { AddNewUser: { path: "adduser/:address/:name/:command?", parse: { address: (address) => `${address}`, command: (command) => `${command}`, name: (name) => `${name}`, }, }, }, }, Settings: { path: "settings", }, }, }, getStateFromPath(path, options) { const state = getStateFromPath(path, options); // 根据当前匹配的栈,处理参数 return { ...state, routes: state.routes.map((route) => { const params = route.params; if (!params?.command) return route; const { command, ...restParams } = params; if (command === "a") { return { ...route, params: { info: restParams, // 如果是SignedOut栈,保留next参数;SignedIn栈不需要 ...(route.name === "AddConnection" ? { next: "AddNewUser" } : {}) }, }; } return { ...route, params: { info: "nothing to see here" }, }; }), }; }, };
3. 兜底方案:手动保存深度链接参数,登录后触发导航
如果还是遇到参数丢失的情况,可以把深度链接参数存到全局Context里,等signedIn变为true时,手动导航到目标页面:
首先,在AuthContext里添加保存参数的状态:
// 扩展AuthContext的value const [deepLinkParams, setDeepLinkParams] = useState(null); const a = { auth, setAuth, deepLinkParams, setDeepLinkParams };
然后在getStateFromPath里提取并保存参数:
getStateFromPath(path, options) { const state = getStateFromPath(path, options); // 提取adduser的参数 const addUserRegex = /adduser\/([^\/]+)\/([^\/]+)\/?([^\/]+)?/; const match = path.match(addUserRegex); if (match) { const [, address, name, command] = match; // 保存到Context(这里需要确保能访问到setDeepLinkParams,比如把它作为参数传入,或者用useContext在外部处理) setDeepLinkParams({ address, name, command }); } // 原来的参数处理逻辑 return { ...state, routes: state.routes.map((route) => { // ... 保留之前的参数处理代码 }), }; }
最后,监听signedIn状态变化,手动导航:
useEffect(() => { // 登录完成且有深度链接参数时,导航到AddNewUser if (signedIn && deepLinkParams?.command === "a") { navigationRef.current?.navigate("SignedIn", { screen: "AddNewUser", params: { info: { address: deepLinkParams.address, name: deepLinkParams.name } } }); // 导航后清空参数,避免重复触发 setDeepLinkParams(null); } }, [signedIn, deepLinkParams]);
核心思路回顾
- 等登录状态确定再渲染导航:避免导航容器一开始匹配错误的栈;
- 给目标栈配置对应路径:让深度链接在登录后能正确匹配到SignedIn栈的页面;
- 手动保存参数兜底:确保即使导航状态重置,参数也能传递到目标页面。
这样调整后,myapp://adduser/address/name/a就能在登录完成后,正确跳转到SignedIn栈里的AddNewUser页面,参数也能正常传递啦!
备注:内容来源于stack exchange,提问作者src2012




