How Pass state value from Component to TabNavigator - javascript

I want pass props from component to createBottomTabNavigator via createStackNavigator
const TabsNavigator = createBottomTabNavigator({
'Notification': {
screen: Private,
navigationOptions: () => ({
tabBarIcon:
<Text style={{ color: '#FFFFFF' }}>
3
</Text>
})
}
})
const BaseNavigatorContainer = createAppContainer(
createStackNavigator({
'TABS': { screen: TabsNavigator }
})
);
class BaseNavigator extends Component {
render() {
return (
<BaseNavigatorContainer screenProps={{ BadgeCount: this.state.BadgeCount }} />
)
}
}
export { BaseNavigator };
I want pass this.state.BadgeCount to
3

You can simply pass a connected component as an icon, that will get the badgeCount:
const TabsNavigator = createBottomTabNavigator({
'Notification': {
screen: Private,
navigationOptions: () => ({
tabBarIcon: ({ tintColor }) => (
<TabBarIconWithBadge color={tintColor} />
),
}),
}
})
And your icon component will look:
const TabBarIconWithBadge = props => (
<Icon color={props.color} />
<Text style={...}>{props.badgeCount}</Text>
);
const mapStateToProps = state => {
return {
badgeCount: state.notifications.badgeCount
};
};
export default connect(mapStateToProps)(TabBarIconWithBadge);

Related

how to change header title in react native functional component?

i am using react-navigation v4 and i want to change the title and the approach i am using is slow while rendering(title that is set in the stack navigator is rendered first and then new one is rendered),is there better way i can render only the new one
export default NewsList = ({ results, navigation}) => {
return <View >
<FlatList
data={results}
keyExtractor={result => result.id}
renderItem={({ item }) => {
return (
<TouchableOpacity
onPress={() => navigation.navigate( 'news',title: item.title)}>
<NewsCard result={item} />
</TouchableOpacity>)
}}
/>
</View>
};
////////////////////////////////////////////////////////////////////
export default NewsScreen = ({ navigation}) => {
NewsScreen.navigationOptions = {
title: navigation.getParam("title");,
};
}
////////////////////////////////////////////////////////////////////
const NewsStack = createStackNavigator({
NewsList :NewsList,
News :NewsScreen
},{
initialRouteName:'NewsList',
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#4BB5C3',
},
},
navigationOptions: {
tabBarLabel: 'NewsList',
},
});
export default createAppContainer(NewsStack);
Ciao, try to set title before navigate into NewsList like this:
export default NewsList = ({ results, navigation}) => {
return <View >
<FlatList
data={results}
keyExtractor={result => result.id}
renderItem={({ item }) => {
return (
<TouchableOpacity
onPress={() => {
navigation.setParams({ otherParam: item.title });
navigation.navigate('news');
}
}>
<NewsCard result={item} />
</TouchableOpacity>)
}}
/>
</View>
};
And I think you could remove navigationOptions in NewsScreen.

How can 'this.state.userName' in constructor can be fetched from 'contentComponent' to be placed in a header section of a drawer in react-navigation?

I have a variable 'this.state.userName' in a constructor obtained from AsyncStorage which log perfect at constructor. I want it to be rendered in the header of navigation drawer of react-navigation. I am so mush messed up with the flow as i am new to react-native. I already wasted entire day. The result on the header is null or no any text is shown , No any error too.
The callbacks of setState of 'this.setState.userName':
06-15 00:40:22.211 20510 29463 I ReactNativeJS: { userName: 'Ramesh mike' }
I have tried the following structure:
class ScreensSetup extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
constructor(props) {
super(props);
AsyncStorage.getItem('KeyUserName').then(value =>{
this.setState({ userName: value}, () => console.log(this.state) );
});
AsyncStorage.getItem('KeyUserEmail').then(value =>{
this.setState({ userEmail: value });
});
AsyncStorage.getItem('KeyUserProfilePicture').then(value =>{
this.setState({ userProfilePicture: value });
});
}
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={this.toggleDrawer}
style={{padding: 15,}}
>
<Icon ios="ios-menu" android="md-menu" size={30} color="white" />
</TouchableOpacity>
</View>
);
}
}
const FirstStackNavigator = createStackNavigator({
First: {
screen: Dashboard,
navigationOptions: ({ navigation }) => ({
title: 'Dashboard',
headerLeft: <ScreensSetup navigationProps={navigation} />,
headerStyle: {
backgroundColor: 'rgb(216,21,88)',
},
headerTintColor: 'white',
}),
},
});
const SecondStackNavigator = createStackNavigator({
Second: {
screen: Workorders,
................
});
const ThirdStackNavigator = createStackNavigator({
Third: {
screen: Projects,
.............
});
const FourthStackNavigator = createStackNavigator({
Fourth: {
screen: Settings,
...............
});
DrawerContent = (props) => {
return (
<View>
<View style={{ backgroundColor: 'rgb(216,21,88)', height: 160,}}>
<Text>{this.state.userName}</Text> //No display of userName
</View>
<DrawerItems {...props} />
</View>
)
}
const DrawerNavigator = createDrawerNavigator(
{
Dashboard: {
//Title
screen: FirstStackNavigator,
navigationOptions: {
drawerLabel: 'Dashboard',
drawerIcon: () => (
<Icon ios="ios-heart" android="md-heart" size={30} color="black" />
),
},
},
Workorders: {
...
},
Projects: {
...
},
Settings: {
...
},
},
{
contentComponent: DrawerContent,
initialRouteName: 'Dashboard',
drawerWidth: 280,
drawerPosition: 'left',
gesturesEnabled: false,
headerMode: 'float',
contentOptions: {
labelStyle: {
color: 'black'
}
}
},
);
const styles = StyleSheet.create({...})
export default DrawerNavigator
You can try the following:
Promise.all([
AsyncStorage.getItem('KeyUserName'),
AsyncStorage.getItem('KeyUserEmail'),
AsyncStorage.getItem('KeyUserProfilePicture')
]).then(
([userName,userEmail,userProfilePicture])=>
this.setState({ userName,userEmail,userProfilePicture })
)

React Native two drawers on one screen

I have an app that needs to be able to use two drawer navigators, one on the left and on on the right side of the header.
I am at the point where I can get both drawers to open with the slide gesture, however I need to be able to open it programmatically. I have found the navigation.openDrawer() function only works with one of the drawers and not the other because it is only able to use one of the navigation props (whichever comes first) from my drawer navigators.
Below are my rendering functions:
const LeftStack = createStackNavigator(
{
LeftDrawerStack
},
{
navigationOptions: ({navigation}) => ({
headerLeft: (
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<Icon style={{marginLeft: 10}} name='menu'/>
</TouchableOpacity>
)
})
}
);
const RightStack = createStackNavigator(
{
RightDrawerStack
},
{
navigationOptions: ({navigation}) => ({
headerRight: (
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<Icon style={{marginRight: 10}} name='ios-bulb'/>
</TouchableOpacity>
)
})
}
);
export const RouteStack = createStackNavigator(
{
screen: LoginScreen,
navigationOptions: ({navigation}) => ({
header: null
}),
LeftStack,
RightStack
}
);
and here are my drawer routes:
export const LeftDrawerStack = createDrawerNavigator(
{
Dashboard: {
screen: DashboardScreen
},
History: {
screen: HistoryScreen
},
Privacy: {
screen: PrivacyPolicyScreen
},
TermsAndConditions: {
screen: TermsAndConditionsScreen
}
}, {
initialRouteName: 'Dashboard',
contentComponent: LeftDrawerScreen
}
);
export const RightDrawerStack = createDrawerNavigator(
{
LeftDrawerStack,
Settings: {
screen: SettingsScreen
}
}, {
drawerPosition: 'right',
contentComponent: RightDrawerScreen
}
);
Here is a picture of what I have the navigation looking like so far, however both of the hamburger menus are opening up the same menu on the right instead of one menu on their respective sides.
I may be missing some parts but I will be sure to post more info if I forgot any!
I was able to do this with the following setup (try to make changes to your structure to be like this):
const LeftDrawer = createDrawerNavigator(
{
LeftDrawer: MyStackNavigator,
},
{
getCustomActionCreators: (route, stateKey) => { return { toggleLeftDrawer: () => DrawerActions.toggleDrawer({ key: stateKey }) }; },
drawerPosition: 'left',
contentComponent: MyLeftDrawer
}
);
const RightDrawer = createDrawerNavigator(
{
Drawer: LeftDrawer,
},
{
getCustomActionCreators: (route, stateKey) => { return { toggleRightDrawer: () => DrawerActions.toggleDrawer({ key: stateKey }) }; },
drawerPosition: 'right',
contentComponent: MyRightDrawer
}
);
export const RootNavigator = createStackNavigator(
{
Login: Login,
Home: RightDrawer
},
{
initialRouteName: 'Login',
navigationOptions: { header: null, gesturesEnabled: false }
}
);
The key is getCustomActionCreators. It allows you to call the function from any screen in MyStackNavigator like this: this.props.navigation.toggleLeftDrawer();.
This is solution I do
Step 1: Create two drawer navigation and nest them together
Step 2: Store first drawer navigation in other place (Singleton)
// Drawer 1
import ContentLeftMenu from '#components/ContentLeftMenu';
import { createDrawerNavigator } from '#react-navigation/drawer';
import * as React from 'react';
import DrawerCart from './DrawerCart';
import { setNavigationDrawerHome } from './RootNavigation';
import { isTablet } from 'react-native-device-info';
import MainStack from './MainStack';
const Drawer = createDrawerNavigator();
export default function DrawerHome() {
return (
<Drawer.Navigator
initialRouteName="DrawerCart"
drawerContent={() => <ContentLeftMenu />}
screenOptions={({ navigation, route }) => {
setNavigationDrawerHome(navigation)
}}
>
<Drawer.Screen name="DrawerCart" component={isTablet ? DrawerCart : MainStack} />
</Drawer.Navigator>
);
}
// Drawer 2
import CartScreen from '#features/cart/CartScreen';
import { createDrawerNavigator } from '#react-navigation/drawer';
import * as React from 'react';
import MainStack from './MainStack';
const Drawer = createDrawerNavigator();
export default function DrawerCart(props) {
return (
<Drawer.Navigator
initialRouteName="MainStackCart"
drawerContent={() => <CartScreen />}
drawerPosition='right'
>
<Drawer.Screen name="MainStackCart" component={MainStack} />
</Drawer.Navigator>
);
}
// set navigation of drawer 1 with navigationDrawerHome
let navigationDrawerHome = null
export const setNavigationDrawerHome = (navigation) => {
navigationDrawerHome = navigation
}
export const getNavigationDrawerHome = () => {
return navigationDrawerHome
}
And when I use in Mainstack I when open Drawer 1 in left I use navigationDrawerHome, with drawer 2 just use navigation props
const Stack = createStackNavigator();
function MainStack() {
const navigationDrawerHome = getNavigationDrawerHome()
return (
<Stack.Navigator
screenOptions={({ navigation, route }) => ({
headerLeft: () => <HeaderLeft />,
headerTitleAlign: 'center',
})}>
<Stack.Screen
name="home_user_tab"
component={HomeUserTabs}
options={({ navigation, route }) => ({
headerLeft: () => {
return (
<ButtonIcon
onPress={() => navigationDrawerHome.openDrawer()}
style={styles.buttonLeft}
icon={images.ic_left_menu}
/>
)
},
headerTitle: () => <LogoHeader />,
headerRight: () => (<HeaderCardSearch
navigation={navigation}
/>),
// header: null
})}
/>
</Stack.Navigator>
);
}
const HeaderCardSearch = (props) => {
const { navigation } = props;
return (
<View style={styles.headerRight}>
<ButtonIcon
onPress={() => navigation.openDrawer()}
style={styles.buttonCart}
icon={images.ic_cart}
/>
<ButtonIcon
onPress={() => navigate('search')}
style={styles.buttonSearch}
icon={images.ic_search}
/>
</View>
)
};
I managed to programmatically open both drawers this way:
// Opens left drawer
this.props.navigation.openDrawer();
// Opens right drawer
this.props.navigation.dangerouslyGetParent().dangerouslyGetParent().openDrawer();
And my navigation container looks like this:
static container = (): NavigationContainer => createDrawerNavigator({
right: createDrawerNavigator({
left: DeviceControlContainer
}, {
contentComponent: HistoryDrawerContainer,
overlayColor: drawerOverlayColor()
})
}, {
drawerPosition: 'right',
overlayColor: drawerOverlayColor(),
navigationOptions: DeviceControlScreen.navigationOptions,
contentComponent: DeviceControlDrawer
});
Got inspired from Anh Devit solution, here is mine. I'm using a header bar across the app without a Stack Navigator, so had to go a slightly different route.
For my RootNavigator, I put my Header above my first drawer. I use useState so when I pass down the navigation objects as props, the AppHeader can re-render correctly when the Drawers have been initialized.
import React, { useState } from "react";
import { NavigationContainer } from "#react-navigation/native";
import LeftDrawer from "./LeftDrawer";
import AppHeader from "./AppHeader";
const RootNavigator = () => {
const [navigationLeftDrawer, setNavigationLeftDrawer] = useState(null);
const [navigationRightDrawer, setNavigationRightDrawer] = useState(null);
return (
<NavigationContainer>
<AppHeader
navigationLeftDrawer={navigationLeftDrawer}
navigationRightDrawer={navigationRightDrawer}
/>
<LeftDrawer
navigationLeftDrawer={(navigation) =>
setNavigationLeftDrawer(navigation)
}
navigationRightDrawer={(navigation) =>
setNavigationRightDrawer(navigation)
}
/>
</NavigationContainer>
);
};
export default RootNavigator;
Here I'm creating my LeftDrawer, in which the RightDrawer will be nested. Notice setting the navigationLeftDrawer when the Drawer inits. Also, navigationRightDrawerhas to be passed down as a param and not a prop.
import React, { useContext } from "react";
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItem,
} from "#react-navigation/drawer";
import RightDrawer from "./RightDrawer";
const LeftDrawer = ({ navigationLeftDrawer, navigationRightDrawer }) => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
screenOptions={({ navigation }) => {
navigationLeftDrawer(navigation);
}}
drawerContent={(props) => {
const { navigate } = props.navigation;
return (<RightDrawerItems />)
);
}}
>
<Drawer.Screen
name="AccountDrawer"
component={RightDrawer}
initialParams={{ navigationRightDrawer }}
/>
</Drawer.Navigator>
);
export default LeftDrawer;
Likewise in RightDrawer, passing up navigationRightDrawer with the right navigation object.
import React from "react";
const RightDrawer = ({ route }) => {
const Drawer = createDrawerNavigator();
const { navigationRightDrawer } = route.params;
return (
<Drawer.Navigator
drawerPosition="right"
screenOptions={({ navigation }) => {
navigationRightDrawer(navigation);
}}
drawerContent={(props) => {
const { navigate } = props.navigation;
return ( <RightDrawerItems />);
}}
>
{userAuth ? (
<>
<Drawer.Screen name={routes.dashboard} component={DashboardScreen} />
</>
) : (
<Drawer.Screen name={routes.home} component={HomeStack} />
)}
<Drawer.Screen name={routes.about} component={AboutScreen} />
<Drawer.Screen name={routes.language} component={LanguageScreen} />
</Drawer.Navigator>
);
};
export default RightDrawer;
Finally, the AppHeader :
import React, { useContext } from "react";
const AppHeader = ({ navigationRightDrawer, navigationLeftDrawer }) => {
if (navigationRightDrawer == null || navigationLeftDrawer == null)
return null;
return (
<View style={styles.container}>
<Icon
name="menu"
color={colors.white}
onPress={() => {
navigationRightDrawer.closeDrawer();
navigationLeftDrawer.toggleDrawer();
}}
/>
{userAuth ? (
<TouchableWithoutFeedback
onPress={() => {
navigationLeftDrawer.closeDrawer();
navigationRightDrawer.toggleDrawer();
}}
>
<Image
style={styles.image}
source={{ uri: userProfile.profilePicture }}
/>
</TouchableWithoutFeedback>
) : (
<Icon
name="person"
color={colors.secondary}
onPress={() => navigationLeftDrawer.navigate(routes.login)}
/>
)}
</View>
);
};
export default AppHeader;

Missing TabBar Review Icon when in Settings screen

When I am on settings screen, I see that the Review Icon (favorite) is missing. It shows when I am back on Review screen. Why is that happening. See the screenshot I took. Pasting relevant code snippet from my project for reference.
const MainNavigator = TabNavigator({
map: { screen: MapScreen },
deck: { screen: DeckScreen },
review: {
screen: StackNavigator({
review: { screen: ReviewScreen },
settings: { screen: SettingsScreen }
})
}
}, {
tabBarPosition: 'bottom',
tabBarOptions: {
labelStyle: { fontSize: 12 }
}
});
class ReviewScreen extends Component {
static navigationOptions = props => {
const {navigation} = props;
const {navigate} = navigation;
return {
tabBarIcon: ({ tintColor }) => {
return <Icon name="favorite" size={30} color={tintColor} />
},
headerTitle: 'Review Jobs',
headerRight: (
<Button
title="Settings"
onPress={() => navigate('settings')}
backgroundColor="rgba(0,0,0,0)"
color="rgba(0, 122, 255, 1)"
/>
)
}
}
Leads here is appreciated.
There is an issue with your code, since you're setting every icon's tintColor in the static navigationOptions as
tabBarIcon: ({tintColor}) => {
return <Icon name="favorite" size={30} color={tintColor}/>
}
and there is none for the Settings Screen, which also expects an Icon as it is inside the TabNavigator, therefore null is being rendered there.
Therefore you need to set the navigationOptions in the Settings Screen as
static navigationOptions = props => {
const {navigation} = props;
const {navigate} = navigation;
return {
tabBarIcon: ({tintColor}) => {
return <Icon name="favorite" size={30} color={tintColor}/>
}
}
}
or you may add the default icons in your App.js navigation file as
screen: TabNavigator({
map: { screen: MapScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="favorite" size={30} color={tintColor}/>
)
}
},
// ....so on
Hope it helps!

TabBar icon don't show and options don't work in react native

I had problem with TabBar react-navigation
| react-navigation 1.0.0-beta.13 |
| react-native 0.48.4|
| node v6.11.4 |
| npm 3.10.10 |
import React from 'react';
import {
Text,
Platform
} from 'react-native';
import { Constants } from "expo"
import {
TabNavigator
} from 'react-navigation';
import { Ionicons } from '#expo/vector-icons';
const MyHomeScreen = ({ navigation }) => (
<Text>HOME</Text>
);
const MyNotificationScreen = ({ navigation }) => (
<Text>NOTIFICATION</Text>
);
MyHomeScreen.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={'md-checkmark-circle'}
size={26}
style={{ color: tintColor }}
/>
),
showIcon: true,
showLabel: false
};
MyNotificationScreen.navigationOptions = {
tabBarLabel: 'People',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={'md-checkmark-circle'}
size={26}
style={{ color: tintColor }}
/>
),
showIcon: true,
showLabel: false
};
const App = TabNavigator(
{
Home: {
screen: MyHomeScreen,
},
Notifications: {
screen: MyNotificationScreen,
},
},
{
tabBarOptions: {
activeTintColor: Platform.OS === 'ios' ? '#e91e63' : '#fff',
},
}
);
export default () => <App />
Live preview
Problem is icon don't show and label is visible but i set showLabel as false.
showIcon & showLabel are options for the TabNavigator itself (under tabBarOptions), not the screen navigationOptions.

Categories

Resources