createStackNavigator и createBottomTabNavigator в React Navigation v.5 - PullRequest
0 голосов
/ 12 февраля 2020

Я новичок в реагировании на нативную версию, и я использую новую реагирующую навигацию v.5 в своем приложении для реагирования на нативную версию. Когда я использую createStackNavigator и createBottomTabNavigator вместе в NavigationContainer, у меня возникают ошибки - «undefined не является объектом» и «Другой навигатор уже зарегистрирован для этого контейнера. Вероятно, у вас есть несколько навигаторов под одним« NavigationContainer »или« Screen ». Убедитесь, что каждый Навигатор находится под отдельным «Экраном» контейнера. (в React Navigation v.5). Скажите пожалуйста, где я не прав?

AppNavigation.tsx

import React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { MainScreen } from "../screens/MainScreen";
import { PostScreen } from "../screens/PostScreen";
import { AboutScreen } from "../screens/AboutScreen";
import { BookedScreen } from "../screens/BookedScreen";
import { CreateScreen } from "../screens/CreateScreen";
import { THEME } from "../theme";
import { Platform } from "react-native";
import { AppHeaderIcon } from "../components/AppHeaderIcon";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

type RootStackParamList = {
  Main: undefined;
  Post: { postId?: string; date?: string; booked?: boolean };
  About: undefined;
  Booked: undefined;
  Create: undefined;
};

const headerButtons = (title: string, icon: string, callback: () => void) => {
  return (
    <HeaderButtons HeaderButtonComponent={AppHeaderIcon}>
      <Item title={title} iconName={icon} onPress={() => callback()} />
    </HeaderButtons>
  );
};

export const AppNavigation = () => {
  const Stack = createStackNavigator<RootStackParamList>();
  const Tab = createBottomTabNavigator();

  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="Main"
        screenOptions={{
          headerTintColor:
            Platform.OS === "android" ? "white" : THEME.MAIN_COLOR,
          headerStyle: {
            backgroundColor:
              Platform.OS === "android" ? THEME.MAIN_COLOR : "white"
          }
        }}
      >
        <Stack.Screen
          name="Main"
          component={MainScreen}
          options={{
            headerTitle: "Мой блог",
            headerRight: () =>
              headerButtons("Сделать фото", "ios-camera", () =>
                console.log("Press camera")
              ),
            headerLeft: () =>
              headerButtons("drower", "ios-menu", () =>
                console.log("Press drower button")
              )
          }}
        />
        <Stack.Screen
          name="Post"
          component={PostScreen}
          options={({ route }) => ({
            headerTitle: `Пост от ${new Date(
              route.params.date
            ).toLocaleDateString()}`,
            headerRight: () =>
              headerButtons(
                "star",
                route.params.booked ? "ios-star" : "ios-star-outline",
                () => console.log("Press star button")
              )
          })}
        />
        <Stack.Screen name="About" component={AboutScreen} />
        <Stack.Screen name="Booked" component={BookedScreen} />
        <Stack.Screen name="Create" component={CreateScreen} />
      </Stack.Navigator>
      <Tab.Navigator>
        <Tab.Screen name="Post" component={PostScreen} />
        <Tab.Screen name="Booked" component={BookedScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
};

App.tsx

import React, { useState } from "react";
import { AppLoading } from "expo";
import { bootstrap } from "./src/bootstrap";
import { AppNavigation } from "./src/navigation/AppNavigation";

export default function App() {
  const [isReady, setIsReady] = useState(false);

  if (!isReady) {
    //AppLoading - пока не завершится выполнение код дальше не пойдет
    return (
      <AppLoading
        startAsync={bootstrap}
        onFinish={() => setIsReady(true)}
        onError={err => console.log('AppLoading error - ', err)}
      />
    );
  }

  return <AppNavigation />;
}

Ответы [ 2 ]

0 голосов
/ 14 февраля 2020

Этот параграф помог мне понять: «Вы можете думать об этом как о наличии отдельных стеков навигации в каждой вкладке, и именно так мы будем моделировать его в React Navigation». Я исправил некоторые неточности в моем коде:

import React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { MainScreen } from "../screens/MainScreen";
import { PostScreen } from "../screens/PostScreen";
import { BookedScreen } from "../screens/BookedScreen";
import { THEME } from "../theme";
import { Platform } from "react-native";
import { AppHeaderIcon } from "../components/AppHeaderIcon";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Ionicons } from "@expo/vector-icons";

type RootStackParamList = {
  Main: undefined;
  Post: { postId?: string; date?: string; booked?: boolean };
  About: undefined;
  Booked: undefined;
  Create: undefined;
};

const Stack = createStackNavigator<RootStackParamList>();

const headerButtons = (title: string, icon: string, callback: () => void) => {
  return (
    <HeaderButtons HeaderButtonComponent={AppHeaderIcon}>
      <Item title={title} iconName={icon} onPress={() => callback()} />
    </HeaderButtons>
  );
};

function PostNavigator() {
  return (
    <Stack.Navigator
      screenOptions={{
        headerTintColor: Platform.OS === "android" ? "white" : THEME.MAIN_COLOR,
        headerStyle: {
          backgroundColor:
            Platform.OS === "android" ? THEME.MAIN_COLOR : "white"
        }
      }}
    >
      <Stack.Screen
        name="Main"
        component={MainScreen}
        options={{
          headerTitle: "Мой блог",
          headerRight: () =>
            headerButtons("Сделать фото", "ios-camera", () =>
              console.log("Press camera")
            ),
          headerLeft: () =>
            headerButtons("drower", "ios-menu", () =>
              console.log("Press drower button")
            )
        }}
      />
      <Stack.Screen
        name="Post"
        component={PostScreen}
        options={({ route }) => ({
          headerTitle: `Пост от ${new Date(
            route.params.date
          ).toLocaleDateString()}`,
          headerRight: () =>
            headerButtons(
              "star",
              route.params.booked ? "ios-star" : "ios-star-outline",
              () => console.log("Press star button")
            )
        })}
      />
    </Stack.Navigator>
  );
}

function BookedNavigator() {
  return (
    <Stack.Navigator
      screenOptions={{
        headerTintColor: Platform.OS === "android" ? "white" : THEME.MAIN_COLOR,
        headerStyle: {
          backgroundColor:
            Platform.OS === "android" ? THEME.MAIN_COLOR : "white"
        }
      }}
    >
      <Stack.Screen
        name="Booked"
        component={BookedScreen}
        options={{
          headerTitle: "Избранное",
          headerRight: () =>
            headerButtons("Сделать фото", "ios-camera", () =>
              console.log("Press camera")
            )
        }}
      />
      <Stack.Screen
        name="Post"
        component={PostScreen}
        options={({ route }) => ({
          headerTitle: `Пост от ${new Date(
            route.params.date
          ).toLocaleDateString()}`,
          headerRight: () =>
            headerButtons(
              "star",
              route.params.booked ? "ios-star" : "ios-star-outline",
              () => console.log("Press star button")
            )
        })}
      />
    </Stack.Navigator>
  );
}

export const AppNavigation = () => {
  const Tab = createBottomTabNavigator();

  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;
            if (route.name === "Post") {
              iconName = focused ? "ios-list-box" : "ios-list";
            } else if (route.name === "Booked") {
              iconName = focused ? "ios-star" : "ios-star-outline";
            }
            return <Ionicons name={iconName} size={size} color={color} />;
          }
        })}
        tabBarOptions={{
          activeTintColor: THEME.MAIN_COLOR,
          inactiveTintColor: "gray"
        }}
      >
        <Tab.Screen name="Post" component={PostNavigator} 
        options={{
          tabBarLabel: 'Все посты'
        }}/>
        <Tab.Screen name="Booked" component={BookedNavigator}
        options={{
          tabBarLabel: 'Избранное'
        }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
};

0 голосов
/ 12 февраля 2020

Это поведение, которое мы хотим от потока аутентификации: когда пользователи входят в систему, мы хотим отбросить состояние потока аутентификации и размонтировать все экраны, связанные с аутентификацией, и когда мы нажимаем кнопку возврата оборудования, мы ожидайте, что не сможете go вернуться к потоку аутентификации. прочтите это - https://reactnavigation.org/docs/en/auth-flow.html#render -the-navigator-content

...