1

所以,我目前正在使用 SwitchNavigator 使用 Navigation v4。我想迁移到 v5,但我无法让它像 Switch 一样工作。我有 3 个堆栈,AuthStack(堆栈导航器)、TabScreens(它是一个底部导航器)、术语(只是一个屏幕),我的 v4 配置是这样的:

  const createRootNavigator = (signedIn = false, terms) => {
  return createAppContainer(
    createSwitchNavigator(
      {
        Auth: { screen: AuthStack, path: 'auth' },
        App: { screen: TabScreens, path: 'app' },
        Terms: { screen: Terms }
      },
      {
        initialRouteName: !signedIn ? !terms ? 'Terms' : 'Auth' : 'App',
        headerMode: 'none',
        defaultNavigationOptions: {
          gestureEnabled: false
        }
      }
    ))
}

因此,当条款屏幕第一次出现并按下一步时,我会自动导航到 Auth,如果我按下 android 后退按钮,则应用程序将关闭,因为 Auth 堆栈是主堆栈。但是在 v5 上不会发生同样的情况。我有一个错误The action 'NAVIGATE' with payload {"name":"Auth"} was not handled by any navigator. Do you have a screen named 'Auth'?

我正在进行的 v5 配置是这样的:

const AuthStack = createStackNavigator();
const Auth = () => (
  <AuthStack.Navigator
    initialRouteName={"SignIn"}>
    <AuthStack.Screen
      name={"SignIn"}
      component={SignIn}
      screenOptions={{ gestureEnabled: false }}
      options={{ headerShown: false }}
    />
  </AuthStack.Navigator>
)

const TermsStack = createStackNavigator();
const TermsScreen = () => (
  <TermsStack.Navigator
    initialRouteName={"Terms"}>
    <TermsStack.Screen
      name={"Terms"}
      component={Terms}
      screenOptions={{ gestureEnabled: false }}
      options={{ headerShown: false }}
    />
  </TermsStack.Navigator>
)


const RootScreens = () => {
  const signedIn = mySDK.isAuthorized();
  const terms = myApi.getTerms();

  return (
    <NavigationContainer>
      {!signedIn ?
        <>
          {!terms ?
            <TermsScreen />
            :
            <Auth />
          }
        </>
        :
        // <App />
        <Auth />
      }
    </NavigationContainer>
  )
};

export default RootScreens;

究竟是什么问题?

4

1 回答 1

1

所以,我终于设法让它工作了。下面是一个演示代码。

import TabScreens from './TabScreens';
        
const AuthStack = createStackNavigator();
const Auth = () => (
<AuthStack.Navigator
        initialRouteName={"LoginMethods"}>
        <AuthStack.Screen
          name={"LoginMethods"}
          component={LoginMethods}
          screenOptions={{ gestureEnabled: false }}
          options={{
            headerShown: false,
            ...TransitionPresets.ModalSlideFromBottomIOS
          }}
        />
    
        <AuthStack.Screen
          name={"Login"}
          component={Login}
          screenOptions={{ gestureEnabled: false }}
          options={{
            headerShown: false,
            ...TransitionPresets.SlideFromRightIOS
          }}
        />
    
        <AuthStack.Screen
          name={"SignUp"}
          component={SignUp}
          screenOptions={{ gestureEnabled: false }}
          options={{
            headerShown: false,
            ...TransitionPresets.SlideFromRightIOS
          }}
        />
    
        <AuthStack.Screen
          name={"ForgotPassword"}
          component={ForgotPassword}
          screenOptions={{ gestureEnabled: false }}
          options={{
            headerShown: false,
            ...TransitionPresets.SlideFromRightIOS
          }}
        />
    
        <AuthStack.Screen
          name={"ChangePassword"}
          component={ChangePassword}
          screenOptions={{ gestureEnabled: false }}
          options={{
            headerShown: false,
            ...TransitionPresets.SlideFromRightIOS
          }}
        />
      </AuthStack.Navigator>
    );


const TermsStack = createStackNavigator();
const TermsScreen = () => (
  <TermsStack.Navigator
    initialRouteName={"Privacy"}>
    <TermsStack.Screen
      name={"Privacy"}
      component={Privacy}
      screenOptions={{ gestureEnabled: false }}
      options={{
        headerShown: false,
        ...TransitionPresets.SlideFromRightIOS
      }}
    />
    <TermsStack.Screen
      name={"Terms"}
      component={Terms}
      screenOptions={{ gestureEnabled: false }}
      options={{
        headerShown: false,
        ...TransitionPresets.SlideFromRightIOS
      }}
    />
  </TermsStack.Navigator>
);


const RootScreens = () => {
  const ref = React.useRef();
  const routeNameRef = React.useRef();

  const signedIn = useSelector(state => state.profile.authorized);
  const showTerms = useSelector(state => state.content.terms);

  //***** Save the initial route name *****/
  React.useEffect(() => {
    routeNameRef.current = signedIn ? 'App' : !showTerms ? 'Terms' : 'Auth';
  }, []);
  //***** Save the initial route name *****/

  const [initialState, setInitialState] = React.useState();

  return (
    <NavigationContainer
      ref={ref}
      initialState={initialState}
      onStateChange={(state) => {
        const prevScreen = routeNameRef.current;
        const currentScreen = getActiveRouteName(state);
        if (prevScreen !== currentScreen) {
          // sendEvent('screen:' + currentScreen, false);
        }
        // Save the current route name for later comparision
        routeNameRef.current = currentScreen;
      }}>
      {
    signedIn ?
        (
            <TabScreens />
        )
        : !showTerms ?
            (
                <TermsScreen />
            )
            :
            (
                <Auth />
            )
}
    </NavigationContainer>
  )
};

正如你在这里看到的,我们已经实现了 React 所称的动态导航。我们的 redux 存储中有一些值,当它们更改时,导航容器会根据情况动态重新渲染(内联 if-else 条件)。因此,例如在应用程序第一次打开时,我们会显示条款屏幕(useSelector(state => state.content.terms) 为 false),当我们按下按钮接受条款时,我们会以 true 发送该操作。然后应用程序现在知道 showTerms 为真,但 signIn 仍然为假,因此它进入登录屏幕。当我们按下登录按钮并且在我们的服务器的登录过程完成之后,我们将 signIn 变量发送为 true,并且应用程序将自己导航到其他屏幕(主应用程序的 Tabscreens)。

请记住,我没有提到导航到那些堆栈(术语、身份验证)的任何地方,而只是一个 redux 调度操作。那是因为我们不需要导航到它们,调度是这里唯一的选择,如果我们尝试从一个堆栈导航到另一个堆栈,那么我们将得到一个红屏。

于 2020-08-05T09:33:17.620 回答