反应本机抽屉导航器未打开

React native drawer navigator not opening

我正在构建一个 React 本机应用程序并使用 React Navigation v6 库。我已经构建了一个在大多数情况下都可以正常工作的 React 导航器,但是在导航到某个页面时我遇到了这个错误。

我有一个堆栈导航器:

   <NavigationContainer>

      <Stack.Navigator >
        <Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
        <Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
        <Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />

        <Stack.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{ header: () => <Header/> }} />

        <Stack.Screen name='HomeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
      </Stack.Navigator>
    </NavigationContainer>

抽屉导航器:

    <Drawer.Navigator screenOptions={{
        drawerStyle: {
          backgroundColor: 'white',
          zIndex: 100
        },
        drawerPosition: 'right'
      }}>
        <Drawer.Screen name='Search cocktails' component={HomeScreen} options={{headerShown: false}} />
        <Drawer.Screen name='Profile' component={ProfileScreen} options={{headerShown: false}} />
        <Drawer.Screen name='Publish a recipe' component={PublishRecipeScreen} options={{headerShown: false}} />

        <Drawer.Screen name='Favorites' component={FavoritesScreen} options={{headerShown: false}} />
        <Drawer.Screen name='Published recipes' component={PublishedRecipesScreen} options={{headerShown: false}} />
        <Drawer.Screen name='Log out' component={LandingScreen} options={{headerShown: false}} />
    </Drawer.Navigator>

导航到 CocktailDetailScreen 时出现问题,问题是抽屉打不开。抽屉是从 header 组件(由 CocktailDetailScreen、homeScreen 和抽屉内的所有屏幕共享)打开的,我使用 navigation.dispatch(DrawerActions.toggleDrawer()) 打开它。这在除此屏幕外的所有屏幕上都可以正常工作。

我想如果我从堆栈导航器中删除 CocktailDetailScreen 并将其添加到抽屉导航器,那么抽屉会正常打开。但我不想要这个,因为这个页面只能通过通过其他屏幕访问,而不是直接从“菜单”/导航器访问。

我确信这是可能的,但我不明白我做错了什么。也许我没有正确嵌套导航器或者屏幕根本不应该在导航器中?

完整代码在这里:https://github.com/coccagerman/mixr

Drawer Navigator 嵌套在 Stack Navigator 中,下面的屏幕可以访问抽屉特定操作(打开、关闭或切换)

  • 搜索鸡尾酒
  • 简介
  • 发布食谱
  • 收藏夹
  • 已发布的食谱
  • 注销

因为它们是 children 抽屉导航器。

要使所有屏幕都可以访问抽屉操作,抽屉必须是所有导航器的parent。

让我们重构我们的代码如下。


const PublicStack = (
  <Stack.Navigator>
    <Stack.Screen
      name="LandingScreen"
      component={LandingScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="LoginScreen"
      component={LoginScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="RegisterScreen"
      component={RegisterScreen}
      options={{ headerShown: false }}
    />

    <Stack.Screen
      name="CocktailDetailScreen"
      component={CocktailDetailScreen}
      options={{ header: () => <Header /> }}
    />

    <Stack.Screen
      name="HomeScreen"
      component={DrawerNavigator}
      options={{ header: () => <Header /> }}
    />
  </Stack.Navigator>
);

const ProtectedStack = () => (
  <Stack.Navigator>
    <Stack.Screen
      name="Search cocktails"
      component={HomeScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="Profile"
      component={ProfileScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="Publish a recipe"
      component={PublishRecipeScreen}
      options={{ headerShown: false }}
    />

    <Stack.Screen
      name="Favorites"
      component={FavoritesScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="Published recipes"
      component={PublishedRecipesScreen}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="Log out"
      component={LandingScreen}
      options={{ headerShown: false }}
    />
  </Stack.Navigator>
);

const MainStack = () => {
  // Mocked logic for authentication, Implement actually logic
  const isLoggedIn = true;

  return (
    <NavigationContainer>
      <Drawer.Navigator
        screenOptions={{
          drawerStyle: {
            backgroundColor: "white",
            zIndex: 100,
          },
          drawerPosition: "right",
        }}
      >
        {isLoggedIn ? (
          <Drawer.Screen
            name="ProtectedStack"
            component={ProtectedStack}
            options={{ header: () => <Header /> }}
          />
        ) : (
          <Drawer.Screen
            name="PublicStack"
            component={PublicStack}
            options={{ header: () => <Header /> }}
          />
        )}

        {/* This screen can be accessible even if when user is not authenticated */}

        <Drawer.Screen
          name="CocktailDetailScreen"
          component={CocktailDetailScreen}
          options={{ header: () => <Header /> }}
        />
      </Drawer.Navigator>
    </NavigationContainer>
  );
};


这是您要求的参考、重构和结构导航。

https://reactnavigation.org/docs/nesting-navigators/#navigator-specific-methods-are-available-in-the-navigators-nested-inside

探索更多

我的实现如下:

import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { createDrawerNavigator } from '@react-navigation/drawer'

import * as React from 'react'

import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
import FavoritesScreen from '../screens/FavoritesScreen'
import PublishedRecipesScreen from '../screens/PublishedRecipesScreen'

import Header from '../components/Header'

import { RootStackParamList } from '../types'

export default function Navigation() {

  const Stack = createNativeStackNavigator<RootStackParamList>()
  const Drawer = createDrawerNavigator()

  const isLoggedIn = false

  const loginStack = () => (
    <Stack.Navigator >
      <Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
      <Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
      <Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
    </Stack.Navigator>
  )

  return (
    <NavigationContainer>
      <Drawer.Navigator screenOptions={{
        drawerStyle: { backgroundColor: 'white' },
        drawerPosition: 'right'
      }}>

        {!isLoggedIn ? (
          <Stack.Screen
            name="PublicStack"
            component={loginStack}
            options={{headerShown: false}}
          /> )
        :
        (<>
          <Drawer.Screen name='Search cocktails' component={HomeScreen} options={{ header: () => <Header/> }} />
          <Drawer.Screen name='Profile' component={ProfileScreen} options={{ header: () => <Header/> }} />
          <Drawer.Screen name='Publish a recipe' component={PublishRecipeScreen} options={{ header: () => <Header/> }} />
          <Drawer.Screen name='Favorites' component={FavoritesScreen} options={{ header: () => <Header/> }} />
          <Drawer.Screen name='Published recipes' component={PublishedRecipesScreen} options={{ header: () => <Header/> }} />
          <Drawer.Screen name='Log out' component={LandingScreen} options={{ header: () => <Header/> }} />

          <Drawer.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{
            header: () => <Header/>,
            drawerLabel: () => null,
            title: undefined
          }} />
        </>
        )}

      </Drawer.Navigator>
    </NavigationContainer>
  )
}

我将抽屉导航器设为主导航器,并为登陆、注册和登录页面制作了一个不同的堆栈导航器。

在抽屉中,我将这个单独的堆栈导航器作为子屏幕并将其作为组件传递给堆栈导航器。

抽屉屏幕与我之前使用的相同,除了现在 CocktailDetailScreen 也是抽屉导航器的子项,多亏了它我现在可以对其进行操作。因为我不希望通过导航器菜单访问该屏幕,所以我只是不使用 drawerLabel: () => null, title: undefined