React Nativeを使用してモバイルアプリケーションを構築しており、React Navigationを使用してアプリケーション内にナビゲーターを構築しています。React =ナビゲーションは、スタックナビゲーター内にもあるドロワー内のネストされたタブバーを処理するための優れた方法を提供してくれました。
問題は、コンポーネントをタブバーに提供できるように指定する必要があることです。 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
}
})
ありがとう
ここにルートコード
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);
ここでは、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;
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>
);
}
}
このqが投稿されるのは久しぶりですが、まだこれを見ている人がいるのなら。このライブラリの代わりにreact-native-navigation
を使用したいと思います。