代码之家  ›  专栏  ›  技术社区  ›  ozer

React Native-使用React Navigation动态创建导航器

  •  8
  • ozer  · 技术社区  · 8 年前

    我正在使用React Native构建一个移动应用程序,并使用React Navigation在我的应用程序中构建一个导航器。React导航为我提供了一种很好的方法来处理抽屉中嵌套的选项卡栏,抽屉也位于堆栈导航器中。

    问题是我需要指定组件,以便可以将其提供到选项卡栏中。假设我们必须从API中获取一些类别,我们不知道数据中有多少类别。此外,我无法理解,即使我尝试在开始时获取数据,导航器和redux配置也会在开始时进行,这意味着应用程序必须知道这些选项卡导航器中的组件。即使我从API中获取数据,我也无法理解如何创建多个组件,同时停止应用程序配置。

    下面的代码只是演示了如何实现选项卡栏。此代码在索引中工作。因为正如我前面提到的,应用程序必须知道导航器中的组件。

    const TabStack = TabNavigator({
        Food: { screen: FoodStack},
        Drink : { screen: DrinkStack },
        HealthCare : { screen: SnackProducts },
        Snacks: { screen: SnackStack },
    },
        {
            tabBarComponent : props => <CustomTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Food',
            swipeEnabled: true,
            tabBarOptions : {
     
                scrollEnabled : true
            }
    })

    谢谢

    这里是根代码

    import { AppRegistry } from 'react-native';
    import React from 'react';
    
    import { Text, Image, ScrollView, View, List, ListItem, TouchableWithoutFeedback } from 'react-native';
    import { Icon, Avatar } from 'react-native-elements';
    
    import { Provider, connect } from 'react-redux'
    import thunkMiddleware from 'redux-thunk'
    import { createStore, applyMiddleware, combineReducers } from 'redux';
    import {
        addNavigationHelpers, StackNavigator,
        DrawerNavigator,
        DrawerItems,
        TabNavigator,
        TabView,
        TabBarTop,
        NavigationActions
    } from 'react-navigation';
    
    // importing starting screen 
    
    import StartingContainer from './src/containers/StartingScreen/StartingContainer';
    
    // Menu Containers
    import MenuCredentials from './src/containers/MenuCredentials';
    
    // Containers
    import LoginContainer from './src/containers/LoginContainer';
    import PhoneNumberValidation from './src/containers/SubLoginContainers/PhoneNumberValidation';
    import MainOrderContainer from './src/containers/OrderContainers/MainOrderContainer';
    import MainCartContainer from './src/containers/CartContainers/MainCartContainer';
    
    // Components 
    // Login Components
    import SMSLogin from './src/containers/SubLoginContainers/SMSLogin';
    
    // Profil Components
    import Profil from './src/components/ProfileComponents/Profile';
    import AdressComponent from './src/components/ProfileComponents/AdressComponent';
    import SettingsComponent from './src/components/ProfileComponents/SettingsComponent';
    import creditCardComponent from './src/components/ProfileComponents/creditCardComponent';
    // Reducers
    import initialReducer from './src/reducers/initialReducer';
    import cartReducer from './src/reducers/cartReducer';
    import starterReducer from './src/reducers/starterReducer';
    
    // import tab bar containers
    
    import FoodProducts from './src/containers/TabBarContainers/FoodProducts';
    import HealthProducts from './src/containers/TabBarContainers/HealthProducts';
    import SnackProducts from './src/containers/TabBarContainers/SnackProducts';
    
    // Building Navigation
    import MenuItem from './src/containers/MenuItemContainer/MenuItem';
    import CustomTabItems from './src/containers/CustomTabItems';
    import CustomSubTabItems from './src/containers/CustomSubTabItems';
    
    import DrawerButton from './src/containers/DrawerButton';
    
    // Tab Bar Navigation
    const ChocolateStack = TabNavigator({
        Tadelle: { screen: MenuItem},
        Milka: { screen: MenuItem},
    },
        {
            tabBarComponent : props => <CustomTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Tadelle',
            swipeEnabled: true,
            tabBarOptions: {
                scrollEnabled: true
            },
    
    })
    const SnackStack = TabNavigator({
        Çikolatalar: { screen: MenuItem},
        Gofretler: { screen: MenuItem},
        Krakerler: { screen: MenuItem},
        Bisküviler: { screen: MenuItem},
        Kuruyemişler: { screen: MenuItem},
    },
        {
            tabBarComponent : props => <CustomSubTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Çikolatalar',
            swipeEnabled: true,
            tabBarOptions : {
                scrollEnabled : true
            }
    })
    
    const DrinkStack = TabNavigator({
        'Gazlı İçecekler': { screen: MenuItem},
        'Soğuk Çaylar': { screen: MenuItem},
        'Alkol': { screen: MenuItem},
        'Süt Ürünleri': { screen: MenuItem},
        'Spor İçecekleri': { screen: MenuItem},
    },
        {
            tabBarComponent : props => <CustomSubTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Alkol',
            swipeEnabled: true,
            tabBarOptions : {
                scrollEnabled : true
            }
    })
    
    const FoodStack = TabNavigator({
        Sandviç : { screen: MenuItem},
        Çorba: { screen: MenuItem},
    },
        {
            tabBarComponent : props => <CustomSubTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Sandviç',
            swipeEnabled: true,
            tabBarOptions : {
                scrollEnabled : true
            }
    })
    
    
    const TabStack = TabNavigator({
        Food: { screen: FoodStack},
        Drink : { screen: DrinkStack },
        Health : { screen: SnackProducts },
        Snacks: { screen: SnackStack },
    },
        {
            tabBarComponent : props => <CustomTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Food',
            swipeEnabled: true,
            tabBarOptions : {
                tabStyle : {
                    width : 250
                },
                scrollEnabled : true
            }
    })
    
    
    
    
    // cart navigation will be drawernavigator and drawerItems will be custom !!
    const CartNavigation = StackNavigator({
        Cart: {
            screen: MainCartContainer,
        }
    },
        {
            headerMode: 'float',
            navigationOptions: ({ navigation }) => ({
                title: 'Sepet',
                headerLeft: <Icon
                    name='arrow-back'
                    color='#517fa4'
                    onPress={() => navigation.navigate('drawerStack')}
                />,
                headerRight:
                <Icon
                    name='payment'
                    color='#517fa4'
                    onPress={() => navigation.navigate('drawerStack')}
                />
            })
    
        }
    )
    const DrawerStack = DrawerNavigator({
        Sipariş: { screen: TabStack },
        Profil: { 
            screen: Profil ,
            navigationOptions : ({ navigation }) => ({
                title : 'Profilim',
            })
        },
        Adreslerim: {
            screen: AdressComponent,
            navigationOptions: ({ navigation }) => ({
                title: 'Teslimat Adreslerim'
            })
        },
        Ayarlar: { screen: SettingsComponent }
    },
        {
            drawerPosition: 'left',
            headerMode : 'none',
            navigationOptions: ({ navigation }) => ({
                headerStyle: { backgroundColor: '#87CEFA' },
                headerRight: <Icon
                name='shopping-cart'
                color='#517fa4'
                onPress={() => navigation.navigate('cartStack')}
                />,
            }),
            contentOptions: {
                inactiveTintColor: 'white',
                activeTintColor: 'purple',
                style: {
                    marginTop: 80,
                    marginLeft: 25,
                }
            },
            contentComponent: props => <MenuCredentials {...props} />
    })
    
    const DrawerNavigation = StackNavigator({
        DrawerStack: {
            screen: DrawerStack
        }},
       {
           style : {
               leftDrawerWidth : 40
           },
           index : 0,
           navigationOptions : ({ navigation }) => ({
                headerStyle: { backgroundColor: '#87CEFA' },
                gesturesEnabled : false,
                headerRight : <Icon
                name='shopping-cart'
                color='#517fa4'
                onPress={() => navigation.navigate('cartStack')}
                />,
                headerLeft: <Icon
                name='menu'
                color='#517fa4'
                onPress={() => {
                    console.log(navigation.state.routes[0]);
                    navigation.navigate({
                        key : null,
                        index : 0,
                        action : [
                            navigation.navigate('DrawerToggle')
                        ]
                    })
                }}
                />
           }),
           initialRouteParams : {
               name : 'Welcome'
           }
       } 
    )
    
    const LoginStack = StackNavigator({
        Login: {
            screen: LoginContainer,
            navigationOptions: ({ navigation }) => ({
                title: ' GİZLİ UYGULAMA ! '
            })
        },
        Ss: {
            screen: SMSLogin,
            navigationOptions: ({ navigation }) => ({
                title: ' SMS ONAYI '
            })
        },
        PhoneNumberValidation: {
            screen: PhoneNumberValidation,
            navigationOptions: ({ navigation }) => ({
                title: 'Kaydolma'
            })
        },
        },{
            headerMode : 'none',
            initialRouteName : 'Login'
    })
    
    // IMPORTANT NOTE ***!!!
    // CARRY drawerStack to the PrimaryNavigator !!
    // CHANGE LoginContainer so that it will navigate to the drawerStack
    // NOT FROM ACTION BUT FROM COMPONENT INSIDE COMPONENTWILLUPDATE
    // BY CHANGING isAuth variable in initialReducer !!
    
    const PrimaryNavigator = StackNavigator({
        loginStack: {
            screen: LoginStack
        },
        cartStack: {
            screen: CartNavigation
        },
        drawerStack: {
            screen:  DrawerNavigation
        },
        starter : {
            screen : StartingContainer
        }
    },
        {
            headerMode: 'none',
            title: 'Main',
            initialRouteName : 'starter'
        }
    )
    
    const navReducer = (state, action) => {
        const nextState = PrimaryNavigator.router.getStateForAction(action, state);
        // Simply return the original `state` if `nextState` is null or undefined.
        return nextState || state;
    };
    
    // combining Reducers
    const AppReducer = combineReducers({
        initialR: initialReducer,
        cartR: cartReducer,
        starterR : starterReducer,
        nav: navReducer
    })
    
    // Creating redux store
    
    const store = createStore(
        AppReducer,
        applyMiddleware(thunkMiddleware)
    )
    
    // Navigation initilizator to App
    class App extends React.Component {
        render() {
            return (
                <PrimaryNavigator navigation={addNavigationHelpers({
                    dispatch: this.props.dispatch,
                    state: this.props.nav
                })}
                />
            )
        }
    }
    const mapStateToProps = (state) => ({
        nav: state.nav
    })
    
    const AppWithNavigationState = connect(mapStateToProps)(App);
    
    class brilliantApp extends React.Component{
        render(){
            return(
                <Provider store={store}>
                < AppWithNavigationState />
            </Provider>
            )        
        }
    }
    
    AppRegistry.registerComponent('brilliantApp', () => brilliantApp);
    3 回复  |  直到 8 年前
        1
  •  3
  •   Alexander Vitanov    8 年前

    您的TabStack文件:

    const CATEGORIES = {
      "Food": { screen: FoodStack },
      // ...
    }
    
    export default (screenNames) => {
      const screens = screenNames.reduce((total, name) => ({...total, [name]: CATEGORIES[name]}), {})
      const TabStack = TabNavigator(screens,
        {
            tabBarComponent : props => <CustomTabItems props={props}/>,
            tabBarPosition: 'top',
            animationEnabled : true,
            initialRouteName : 'Food',
            swipeEnabled: true,
            tabBarOptions : {
    
                scrollEnabled : true
            }
      })
      return TabStack
    }
    

    您的根文件:

    import getTabStack from './TabStack'
    
    
    class Root extends Component {
    
        state = {
          categoriesNames: null
        }
    
        componentWillMount() {
          // assuming result is ["Food", "Drink", ... ]
          Api.fetchCategories().then((result) => {
            this.setState({ categoriesNames: result })
          })
        }
    
        render() {
          const { categoriesNames } = this.state
          if (!categoriesNames) {
            return <SplashScreen />
          }
          const TabStack = getTabStack(categoriesNames)
          return (
            <Provider store={store} >
              <TabStack />
            </Provider>
          );
        }
      }
    
        2
  •  3
  •   ozer    8 年前

    在这里,我想发布一个方法,根据我们从一些API等编程获取的数据创建选项卡栏。

    在本例中,我们从API获取数据,这段代码来自顶级组件:

    renderShopTab() {
            const { client } = this.props;
            try {
                const { categories } = client.readQuery({
                    query: gql`
                    {
                        categories{
                            id
                            name
                            products{
                                id
                                name
                                price
                                quantity
                            }
                        }
                    }`
                })
    
                console.log("Categories  :" + categories);
    
                return (
                    <ShopCreator categories={categories} />
                )
    
            } catch (error) {
                console.log("Error occured creating the categories due to the : " + error);
    
                return (
                    <View>
                        <Text>
                            Loading...
                        </Text>
                    </View>
                )
    
            }
    
        }

    此代码段来自选项卡栏的创建者:

    export const ShopCreator = ({ categories }) => {
    
        // This script will create a TabNavigator for categories and StackNavigators for each member of the categories !
    
        let categoryStack = {};
    
        let routes = {};
    
    
        categories.forEach((category) => {
    
            if (category.products.length > 0) {
    
                const { catname } = category.name;
    
                if (category.name != undefined) {
    
                    routes[category.name] = {
                        screen: StackNavigator({
                            'isim': {
                                screen: ProductPage
                            }
                        },{
                            headerMode : 'none',
                            initialRouteParams : {
                                categoryName : category.name,
                                products : category.products
                            }
                        })
                    }
                }
                
            } else {
    
                console.log("This category has no products !");
    
            }
    
        })
    
        console.log("OHA : " + JSON.stringify(routes));
    
        const ShopCatTabNav = TabNavigator(routes, {
            tabBarPosition: 'top',
            tabBarComponent: props => <TabMenuItems props={props} />
        })
    
        return <ShopCatTabNav />
    
    }

    最后,我将向您展示我构建的自定义选项卡导航栏:

    const TabMenuItems = ({props}) => {
    
        const { activeTintColor, tab, tabbar, tabText, inactiveTintColor } = styles;
        const { index } = props.navigation.state;
        return(
            <View>
            <ScrollView contentContainerStyle={{ flex : 1 }} horizontal showsHorizontalScrollIndicator={false} style={{backgroundColor : '#FFAEB9'}}>
            {
                props.navigation.state.routes.length ? (
                    props.navigation.state.routes.map((route,number)=>{
                        const focused = ( index === number ) ? '#1874CD' : '#FF6A6A';
                        const tintColor = focused ? activeTintColor : inactiveTintColor;
                        return (
                            <TouchableWithoutFeedback
                                key={route.key}
                                onPress={() => {
                                    props.jumpToIndex(number)
                                }}
                                delayPressIn={0}
                                >
                                <View style={{marginLeft : 20, marginTop : height / 40, shadowOpacity : 25, alignSelf : 'flex-start' }}>
                                    <Text style={{borderRadius : 5, fontWeight : 'bold', borderWidth :2, paddingTop : 5,color : 'white', height : height/18, width : width/5,textAlign : 'center', backgroundColor : focused, borderStyle: 'dashed',borderColor : '#CD2626'}}>
                                    {props.getLabel({route, number})}
                                    </Text>
                                </View>
                            </TouchableWithoutFeedback>
                        )
                    })
                ) : null
            }
        </ScrollView>
        </View>
        )
    }
    
    export default TabMenuItems;
        3
  •  0
  •   ozer    6 年前

    这个问题发布已经有一段时间了,但如果还有一些人在看这个的话。我宁愿使用 react-native-navigation 取而代之的是这个图书馆。

    推荐文章