You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Navigation中深度链接跳转SignedIn栈页面的参数传递问题

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]);

核心思路回顾

  1. 等登录状态确定再渲染导航:避免导航容器一开始匹配错误的栈;
  2. 给目标栈配置对应路径:让深度链接在登录后能正确匹配到SignedIn栈的页面;
  3. 手动保存参数兜底:确保即使导航状态重置,参数也能传递到目标页面。

这样调整后,myapp://adduser/address/name/a就能在登录完成后,正确跳转到SignedIn栈里的AddNewUser页面,参数也能正常传递啦!

备注:内容来源于stack exchange,提问作者src2012

火山引擎 最新活动