(also asked in https://github.com/react-navigation/react-navigation/issues/4059#issuecomment-453100740)
I have replaced a static TabNavigator with a dynamic one, and things seem to work.
However, props that have been passed as expected are not passed any more the same way.
Any idea how to fix this? Either by having the props passed as in the static solution, or by passing the required props (this.props.navigation).
export default createDrawerNavigator({
Drawer: MainDrawerNavigator,
Main: MainTabNavigator
}, {
contentComponent: props => <Drawer {...props} />,
});
const ProfileStack = createStackNavigator({
Profile: {
screen: Profile,
navigationOptions: () => ({
title: 'Profile'
})
}
}, {
initialRouteName: 'Profile'
});
ProfileStack.navigationOptions = {
tabBarLabel: 'Profile',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name= 'md-person' />
)};
const MainTabNavigator = createBottomTabNavigator({
RequestStack,
ProfileStack
}, {
headerMode: 'none',
initialRouteName: ProfileStack
});
Profile
screen:import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import { Container, Header, Content, Text
} from 'native-base';
export default class Profile extends React.Component {
static navigationOptions = {
header: null
};
constructor(props) {
super(props);
}
render() {
console.log('in Profile. this.props:');
console.log(this.props);
return (
<Container style={styles.container}>
<Header>
<TouchableOpacity
onPress={() => this.props.navigation.openDrawer()}>
<Icon name="md-more" />
</TouchableOpacity>
</Header>
<Content>
<Text>aaa</Text>
</Content>
</Container>
);
}
}
when I replace the above static Tab Navigator with the following Dynamic one, this.props.navigation.openDrawer is not passed and therefore not defined in 'Profile' (Profile doesn't change, the change is only in the bottom tab navigator).
export default class DynamicTabNavigator extends React.Component {
constructor(props) {
super(props);
}
_tabNavigator() {
let tabs = {};
const a = 2;
if (a > 1) { // the actual line is obviously different, I am trying to simplify the example
tabs = { RequestStack, ManageStack, MessagesStack, ProfileStack };
} else {
tabs = { WorkStack, ManageStack, MessagesStack, ProfileStack };
}
console.log('in _tabNavigator. this.props.navigation:');
console.log(this.props.navigation);
return createBottomTabNavigator(tabs, {
headerMode: 'none',
});
}
render() {
const Tabs = this._tabNavigator.bind(this)();
return (
<Tabs/>
);
}
}
in _tabNavigator. this.props.navigation:
Object {
"actions": Object {
"closeDrawer": [Function closeDrawer],
"goBack": [Function goBack],
"navigate": [Function navigate],
"openDrawer": [Function openDrawer],
"setParams": [Function setParams],
"toggleDrawer": [Function toggleDrawer],
},
"addListener": [Function addListener],
"closeDrawer": [Function anonymous],
"dangerouslyGetParent": [Function anonymous],
"dispatch": [Function anonymous],
"getChildNavigation": [Function getChildNavigation],
"getParam": [Function anonymous],
"getScreenProps": [Function anonymous],
"goBack": [Function anonymous],
"isFocused": [Function isFocused],
"navigate": [Function anonymous],
"openDrawer": [Function anonymous],
"router": undefined,
"setParams": [Function anonymous],
"state": Object {
"key": "Main",
"params": undefined,
"routeName": "Main",
},
"toggleDrawer": [Function anonymous],
}
(I expected all props, like for instance, openDrawer, to be the same as for DynamicTabNavigator, and I don't understand why they aren't)
in Profile. this.props:
Object {
"appMode": "WORK_MODE",
"dispatch": [Function anonymous],
"navigation": Object {
"actions": Object {
"dismiss": [Function dismiss],
"goBack": [Function goBack],
"navigate": [Function navigate],
"pop": [Function pop],
"popToTop": [Function popToTop],
"push": [Function push],
"replace": [Function replace],
"reset": [Function reset],
"setParams": [Function setParams],
},
"addListener": [Function addListener],
"dangerouslyGetParent": [Function anonymous],
"dismiss": [Function anonymous],
"dispatch": [Function anonymous],
"getChildNavigation": [Function getChildNavigation],
"getParam": [Function anonymous],
"getScreenProps": [Function anonymous],
"goBack": [Function anonymous],
"isFocused": [Function isFocused],
"navigate": [Function anonymous],
"pop": [Function anonymous],
"popToTop": [Function anonymous],
"push": [Function anonymous],
"replace": [Function anonymous],
"reset": [Function anonymous],
"router": undefined,
"setParams": [Function anonymous],
"state": Object {
"key": "id-1547113035295-8",
"routeName": "Profile",
},
},
"screenProps": undefined,
}
I a not sure how to implement your solution...
TabRoutes
the three screens that you specified in your exampleHere is the code that I wrote based on your example. I am not sure, however, which component is included in CustomTabBar
. Can you elaborate?
import React from 'react';
class CustomTabBar extends React.Component {
render() {
// a tab bar component has a routes object in the navigation state
const { navigation } = this.props;
// appState is extracted from redux state, see below
if (this.props.appState) {
return (
<View>
<???
name='First'
onPress={this.navigationHandler}
focused={navigation.state.index === index}
/>
<???
name='Second'
onPress={this.navigationHandler}
focused={navigation.state.index === index}
/>
</View>
);
} else {
return (
<View>
<???
name='First'
onPress={this.navigationHandler}
focused={navigation.state.index === index}
/>
<???
name='Third'
onPress={this.navigationHandler}
focused={navigation.state.index === index}
/>
</View>
);
}
}
navigationHandler = (name) => {
const {navigation} = this.props;
navigation.navigate(name);
}
}
const mapStateToProps = state => {
const { appState } = state.app;
return { appState };
};
export default connect(mapStateToProps)(CustomTabBar);
react-native-screens provides native primitives to represent screens instead of plain <View> components in order to better take advantage of operating system behavior and optimizations around screens. This capability is used by library authors and unlikely to be used directly by most app developers.
You can also leave the TabNavigator as is, and create a custom TabBar component with custom TabBarItem components. You can connect that custom TabBar to your redux state, and hide/display the custom TabBarItems according your needs.
And then you simply add all possible routes to the TabNavigator as you would always do.
Routes
const TabRoutes = createBottomTabNavigator({
First: {screen: SomeScreen},
Second: {screen: SomeStack},
Third: {screen: AnotherStack}
},{
initialRouteName: 'First',
tabBarComponent: CustomTabBar
});
CustomTabBar
Some basic example on how you could hide the tab bar items, so obviously this needs to be adjusted according your own requirements
import CustomTabBarItem from '...' ;
class CustomTabBar extends React.Component {
render() {
// a tab bar component has a routes object in the navigation state
const {navigation, appState} = this.props;
const routes = navigation.state.routes;
return (
<View style={styles.container}>
// You map over all existing routes defined in TabNavigator
{routes.map((route, index) => {
// This could be improved, but it's just to show a possible solution
if (appState && route.routeName === 'x') {
return <View/>;
} else if (!appState && route.routeName === 'y') {
return <View/>;
}
return (<CustomTabBarIcon
key={route.key}
name={route.routeName}
onPress={this.navigationHandler}
focused={navigation.state.index === index}
appState={appState}
/>);
})}
</View>
);
}
navigationHandler = (name) => {
const {navigation} = this.props;
navigation.navigate(name);
}
}
const styles = StyleSheet.create({
container: {
width: '100%',
flexDirection: 'row'
}
})
const mapStateToProps = (state) => {
return {
appState: state.app.appState // boolean
};
};
export default connect(mapStateToProps)(CustomTabBar);
CustomTabBarItem
class CustomTabBarItem extends React.PureComponent {
render() {
const {name, focused} = this.props;
return (
<View style={styles.tabItem}>
// Some icon maybe
<Text style={/*different style for focused / unfocused tab*/}>{name}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
tabItem: {
flex: 1
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With