【问题标题】:How to implement both DrawerNavigator and StackNavigator如何同时实现 DrawerNavigator 和 StackNavigator
【发布时间】:2018-05-11 10:13:47
【问题描述】:

我正在使用 react-native-navigation 开发一个应用程序,我想在项目中拥有一个 StackNavigator 和一个 DrawerNavigator。所以,我已经在 app.js 中实现了它们,但是应用程序崩溃了,给出了这个错误“开发服务器返回了带有代码的响应错误:500”。我已经分别实现了它们并且它可以工作,但我不能一起实现它们。任何建议?

这是我的 app.js 代码

import React, {
    Component
} from 'react';

import {
    StyleSheet,
    Text,
    View
} from 'react-native';

import {
    createStackNavigator,
    DrawerNavigator,
    DrawerItems
} from "react-navigation";

import {
    Container,
    Header,
    Content,
    Thumbnail,
    Button,
    Body
} from 'native-base';

import Profile from './components/Profile.js';
import Main from './components/Main.js';
import Login from './components/Login.js';
import Product from './components/Product.js';

export default class App extends Component {
    render() {
        return ( 
           <Navapp />
        );
    }
}

const styles = StyleSheet.create({
    // styles here
});

export const Drawer = DrawerNavigator({
    Main: {
        screen: Main
    },
    Profile: {
        screen: Profile
    },
}, {
initialRouteName: 'Main',
contentComponent: CustomDrawer,
drawerPosition: 'Left',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});

export const CustomDrawer = (props) => ( 
    <Container>
        <Header style = {
            styles.headerStyle
        }>
            <Body style = {
                styles.bodyStyle
            }>
                <Thumbnail style = {
                    {
                        height: 100,
                        width: 100
                    }
                }
                source = {
                    require('../image/logo.png')
                }/> 
            </Body> 
        </Header>
        <Content>
            <DrawerItems { ...props}  /> 
        </Content > 
    </Container>
)

export const Navapp = createStackNavigator({
    Login: {
        screen: Login
    },
    Drawer: {
        screen: Drawer
    },
    Product: {
        screen: Product
    },
});

【问题讨论】:

  • 你能解释一下你想要什么,比如应用 UI 吗?
  • 我希望第一页是登录页面,然后在提交登录数据后,他会被重定向到具有 DrawerNavigator 的主页

标签: react-native react-navigation


【解决方案1】:

我的应用程序设置非常相似,这就是我处理它的方式。首先,我创建了一个堆栈导航器,其中包含我希望登录用户看到的路线,并将该导航器放置在抽屉导航器中(如果需要,您可以在其中放置多个)。最后我创建了我的顶级导航器,它的初始路由指向登录页面;登录后,我将用户导航到第二条路线,该路线指向我的抽屉导航器。

实际上它看起来像这样:

// Main Screens for Drawer Navigator
export const MainStack = StackNavigator({
  Dashboard: {
    screen: Dashboard,
    navigationOptions: {
      title: 'Dashboard',
      gesturesEnabled: false,
      headerLeft: null
    }
  },

  Notifications: {
    screen: Notifications,
    navigationOptions: {
      title: 'Notifications'
    }
  }
}, { headerMode: 'screen' } );

// Drawer Navigator
export const Drawer = DrawerNavigator({
  MainStack: {
    screen: MainStack
  }
});


// Main App Navigation
export const AppStack = StackNavigator({
  Login: {
    screen: Login,
    navigationOptions: {
      header: null,
      gesturesEnabled: false
    }
  },

  Drawer: {
    screen: Drawer,
    navigationOptions: {
      header: null,
      gesturesEnabled: false
    }
  }
}, { headerMode: 'none' } );

// In Your App.js
<AppStack />

请注意,在最后一个堆栈导航器中,抽屉屏幕的标题设置为 null;这是因为使用嵌套堆栈导航器有时会遇到标题重复的问题。这将隐藏顶级导航器的标题,并让您显示/自定义嵌套导航器的标题。

【讨论】:

  • 如何将数据从“登录”组件传递到“仪表板”组件?
  • @kalyan711987 这取决于您传递数据的意思。如果您想从登录屏幕导航到仪表板屏幕并同时将道具传递给仪表板组件,您可以执行以下操作:this.props.navigation.navigate('Dashboard', { foo: 'bar', bar: 'foo' }); 然后,在您的仪表板组件中,您可以访问 foobar内:this.props.navigation.state.params
  • @MattyCodes 它给了我错误。 Error: The component for route 'Main' must be a React component.。我被困两天了。
【解决方案2】:

我们可以实现堆栈和抽屉导航的方式可能已经变得更加简单。在这里你们可以参考我的代码。

import * as React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { createDrawerNavigator } from "@react-navigation/drawer";
import MenuComponent from "../MenuComponent";
import DishDetailComponent from "../DishDetailComponent";
import HomeComponent from "../HomeComponent";

/**
 * @author BadalSherpa
 * @function HomeNavigation
 **/

const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();

const HomeNavigation = (props) => {
  return (
    <Stack.Navigator initialRouteName='Home'>
      <Stack.Screen name='Home' component={HomeComponent} />
      <Stack.Screen name='Menu' component={MenuComponent} />
      <Stack.Screen name='Dish-Detail' component={DishDetailComponent} />
    </Stack.Navigator>
  );
};

const MenuNavigation = (props) => {
  return (
    <Stack.Navigator initialRouteName='Home'>
      <Stack.Screen name='Menu' component={MenuComponent} />
    </Stack.Navigator>
  );
};

const DrawerNavigation = () => {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name='Home' component={HomeNavigation} />  //Here is where we are combining Stack Navigator to Drawer Navigator
      <Drawer.Screen name='Menu' component={MenuNavigation} />
    </Drawer.Navigator>
  );
};

export default DrawerNavigation;

然后你可以简单地在 NavigationContainer 中返回它,这将使 Stack 和 Drawer Navigator 一起工作。

<NavigationContainer>
      <HomeNavigation />
 </NavigationContainer>

【讨论】:

  • 这不起作用,让它起作用;因为你要导出&lt;DrawerNavigation /&gt;,所以把它包裹在&lt;NavigationContainer&gt;
  • 另外,如果以下代码对我有更好的帮助:&lt;NavigationContainer&gt; &lt;Drawer.Navigator drawerContent={props =&gt; &lt;SideBar {...props} /&gt;}&gt; &lt;Drawer.Screen name='App' component={App} /&gt; &lt;/Drawer.Navigator&gt; &lt;/NavigationContainer&gt;
  • 是的 shivam jha 我将抽屉导航包装在 NavigationContainer 中。因为我将 DrawerNavigation 作为默认值导入,所以我将它作为 HomeNavigation 导入到我的 MainComponent 中。 &lt;NavigationContainer&gt; &lt;HomeNavigation /&gt; &lt;/NavigationContainer&gt;这里是DrawerNavigation的内容。
【解决方案3】:

这就是我使用它们的方式

const HomeStackNavigator = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    Chat: {
      screen: ChatScreen,
    },
  },
  {
    initialRouteName: 'Home',
    headerMode: 'screen',
  },
);

const MainDrawerNavigator = DrawerNavigator(
  {
    Home: {
      screen: HomeStackNavigator,
    },
  },
  {
    drawerOpenRoute: 'DrawerOpen',
    drawerCloseRoute: 'DrawerClose',
    drawerToggleRoute: 'DrawerToggle',
    contentComponent: SlideMenu,
    navigationOptions: {
      drawerLockMode: 'locked-closed',
    },
  },
);

【讨论】:

  • 谢谢。我试过这个,但登录屏幕有抽屉。如何禁用它?
  • 我希望抽屉只在主屏幕上
  • @tuledev 它给了我错误。 Error: The component for route 'Main' must be a React component.。我被困两天了。
【解决方案4】:

我也有同样的问题,然后我只需要更改我的模拟器并更新版本,它就可以 100% 运行。

【讨论】:

    【解决方案5】:

    这与抽屉导航器控制堆栈导航器的情况略有不同。抽屉中的每个选择都会推送一个子堆栈元素,因此抽屉和堆栈之间存在一对一的匹配。根据我的经验,这是更典型的行为。除了家之外,所有的标题都有一个带有返回导航指示器的标题。

    import React from 'react';
    import {SafeAreaView, StyleSheet} from 'react-native';
    import {
      CompositeNavigationProp,
      NavigationContainer,
    } from '@react-navigation/native';
    import {
      createStackNavigator,
      StackNavigationProp,
    } from '@react-navigation/stack';
    import HomeScreen from './HomeScreen';
    import SettingsScreen from './SettingsScreen';
    import {
      createDrawerNavigator,
      DrawerContentComponentProps,
      DrawerContentOptions,
      DrawerContentScrollView,
      DrawerItem,
      DrawerNavigationProp,
    } from '@react-navigation/drawer';
    
    type NoProps = Record<string, object>;
    export type ScreenNavigationProps = CompositeNavigationProp<
      StackNavigationProp<NoProps>,
      DrawerNavigationProp<NoProps>
    >;
    
    export type DrawerProps = DrawerContentComponentProps<DrawerContentOptions>;
    const Drawer = createDrawerNavigator();
    const Stack = createStackNavigator(); // https://reactnavigation.org/docs/stack-navigator/
    
    /**
     * Render the content of the drawer.  When an item is selected
     * it closes the drawer and pushes an element on the stack nav.
     * @param props
     */
    function CustomDrawerContent(props: DrawerProps) {
      const navigation = (props.navigation as unknown) as ScreenNavigationProps;
    
      const openScreen = (name: string) => () => {
        navigation.navigate('Home', {screen: name});
        navigation.closeDrawer();
      };
    
      return (
        <DrawerContentScrollView {...props}>
          {/* <DrawerItemList {...props} /> */}
          <DrawerItem label="Home" onPress={openScreen('Home')} />
          <DrawerItem label="Settings" onPress={openScreen('Settings')} />
        </DrawerContentScrollView>
      );
    }
    
    /**
     * Render the Home Stack Navigator.
     */
    function HomeStack() {
      return (
        <Stack.Navigator initialRouteName="Home">
          <Stack.Screen
            name="Home"
            component={HomeScreen}
            options={{headerShown: false}}
          />
          <Stack.Screen name="Settings" component={SettingsScreen} />
        </Stack.Navigator>
      );
    }
    
    /**
     * Render the Home Drawer with a custom drawerContent.
     */
    function HomeDrawer() {
      return (
        <Drawer.Navigator
          initialRouteName="Home"
          drawerContent={(props) => <CustomDrawerContent {...props} />}>
          <Drawer.Screen name="Home" component={HomeStack} />
        </Drawer.Navigator>
      );
    }
    
    const App = () => {
      return (
        <SafeAreaView style={styles.app}>
          <NavigationContainer>
            <HomeDrawer />
          </NavigationContainer>
        </SafeAreaView>
      );
    };
    
    const styles = StyleSheet.create({
      app: {flex: 1},
    });
    
    export default App;
    
    

    HomeScreen 可以提供一个菜单来打开抽屉:

      const navigation = useNavigation<ScreenNavigationProps>();
    
      const openDrawer = () => {
        navigation.openDrawer();
      };
    

    【讨论】:

      猜你喜欢
      • 2018-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 2018-07-28
      • 1970-01-01
      相关资源
      最近更新 更多