React Native - 使用React Navigation动态创建Navigator

时间:2017-11-12 20:21:12

标签: react-native react-navigation tabnavigator

我正在使用React Native构建移动应用程序,我正在使用React Navigation在我的应用程序中构建导航器。 React navigation为我提供了一个很好的方法来处理抽屉内的嵌套Tab栏,它也在Stack Navigator中。

问题是我需要指定组件,以便我可以将它们提供到Tab栏中。让我们说我们必须从API中获取一些类别,我们不知道数据中有多少类别。此外,我无法弄清楚即使我尝试在启动时获取数据,导航器和redux配置也会在启动时发生,这意味着应用程序必须知道这些选项卡导航器中的组件。我无法弄清楚即使我从API中获取数据,我如何创建多个组件并停止应用程序配置。

下面的代码,演示了我如何实现标签栏。此代码在index.js中有效,因为正如我之前提到的,应用程序必须知道导航器中的组件。



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
        }
})
&#13;
&#13;
&#13;

由于

这里是根代码

&#13;
&#13;
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);
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:3)

您的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>
      );
    }
  }

答案 1 :(得分:3)

在这里,我想根据我们从某些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;

答案 2 :(得分:0)

发布这个问题已经有一段时间了,但是如果仍然有人在看这个问题。我宁愿使用react-native-navigation代替该库。