React Navigation - undefined is not an object (evaluating 'this.navigation.navigate') - react-native

I am following this tutorial to implement a switch navigator for user authentication: https://snack.expo.io/#react-navigation/auth-flow-v3.
However, this.navigation.navigate appears to undefined when I try to navigate to the next screen.
undefined is not an object (evaluating 'this.props.navigation.navigate')
I am using expo for my app, and I've already looked at the solutions posted to a similar question at React Native - navigation issue "undefined is not an object (this.props.navigation.navigate)" to no avail.
import * as React from 'react';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import profile from './app/screens/profile.js'
import home from './app/screens/home.js'
import createCompetition from './app/screens/create.js'
import explore from './app/screens/explore.js'
import Icon from 'react-native-vector-icons/MaterialIcons'
import login from './app/screens/login.js';
import { f } from './config/config.js';
import { ActivityIndicator, AsyncStorage, Button, StatusBar, StyleSheet, View } from 'react-native';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
/**
* Tab Stack is the Bottom Navigator for the different pages
*/
const TabStack = createBottomTabNavigator(
{
Home: {
screen: home,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="home" size={25} style={{ color: tintColor }} />
),
},
},
Explore: {
screen: explore,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="search" size={25} style={{ color: tintColor }} />
),
}
},
Profile: {
screen: profile,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="person" size={25} style={{ color: tintColor }} />
),
}
},
Create: {
screen: createCompetition,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="add" size={25} style={{ color: tintColor }} />
),
}
},
},
{
tabBarOptions: {
showIcon: true,
showLabel: false,
activeTintColor: 'black',
style: { backgroundColor: 'white', }
},
},
)
/**
* Loading Screen during authorization process
*/
class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
f.auth().onAuthStateChanged(function (user) { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppStack = createStackNavigator({ Home: TabStack });
const AuthStack = createStackNavigator({ Login: login });
const RootStack = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
const App = createAppContainer(RootStack);
export default App;

You are not giving access to this to your _bootstrapAsync function and your onAuthStateChanged callback. Just pass the callback inside of it using arrow function, as it autobinds the current function to the current app this
_bootstrapAsync = async () => {
f.auth().onAuthStateChanged((user) => { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
};

The problem is with function keyword, which doesnt bind this keyword. Better replace it with ES6 arrow functions which implictly binds this to the inner scope :
f.auth().onAuthStateChanged((user) => { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
Hope it helps .feel free for doubts

Related

How Can I touch overflow Middle Button on bottomTab navigation?

I want to Make TabNavigation Using react-navigation.
like that picture.
Here is picture my App. I want to Touch that 'red-section' But it is now work now
I want to active that section. Please tell me how can i do...
Middle Button is more bigger than others
this is my App.js Code. And I made AddButton Component.
const AppContainer = createStackNavigator(
{
default: createBottomTabNavigator(
{
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <AntDesign name="home" size={35} color={tintColor} />
}
},
Post: {
screen: () => null,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<TouchableOpacity size={150}
activeOpacity={1}
style={{
width:75,
height:75,
justifyContent: 'center',
alignItems: 'center',
height:80,
marginBottom:80
}}
>
<AddButton/>
</TouchableOpacity>
),
},
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <MaterialIcons name="person-outline" size={35} color={tintColor} />
}
}
},
{
defaultNavigationOptions: {
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (navigation.state.key === 'Post') {
navigation.navigate('postModal')
} else {
defaultHandler()
}
}
},
tabBarOptions: {
activeTintColor: '#5A2AB7',
inactiveTintColor: '#404040',
showLabel: false,
style: { height: 80 },
}
}
),
postModal: {
screen: PostScreen
}
},
{
mode: 'modal',
headerMode: 'none',
}
)
const AuthStack = createStackNavigator({
Login: LoginScreen,
Register: RegisterScreen
})
export default createAppContainer(
createSwitchNavigator(
{
Loading: LoadingScreen,
App: AppContainer,
Auth: AuthStack
},
{
initialRouteName: "Loading"
}
)
);
here is AddButton.js
import React from 'react'
import {View, StyleSheet, Text, TouchableHighlight, Animated} from 'react-native'
import {FontAwesome5} from '#expo/vector-icons'
export default class AddButton extends React.Component {
render() {
return (
<View style={styles.button} underlayColor='#875EC1'>
<FontAwesome5 name="plus" size= {24} color="#FFF" />
</View>
)
}
}
const styles = StyleSheet.create({
button:{
backgroundColor:'#875EC1',
alignItems:'center',
justifyContent:'center',
width:72,
height:72,
borderRadius:36,
shadowColor:'#875EC1',
shadowRadius:5,
shadowOffset: {height:10},
shadowOpacity:0.3,
elevation:3
}
})

Hide bottom tab naivgation

I have a bottom tab bar that locates in app.js. And I have the class where I want to hide the bottom bar. In page home.js I have 2 classes. 1st one is main (is the list of articles), the second one is for button page navigation (in this class I display articles). How I can hide bottom tab navigation in the second page (where articles are displayed). I have tried tabBarVisible: false, but this does not work. Help me, please.
Code:
// app.js
const TabNavigator = createBottomTabNavigator({
Home:{
screen:Home,
navigationOptions:{
tabBarLabel:'Главная',
tabBarIcon:({tintColor})=>(
<Icon name="ios-home" color={tintColor} size={24} />
)
}
},
Courses:{
screen:Courses,
navigationOptions:{
tabBarLabel:'Courses',
tabBarIcon:({tintColor})=>(
<Icon name="ios-school" color={tintColor} size={24} />
)
}
},
Editor:{
screen:Editor,
navigationOptions:{
tabBarLabel:'Editor',
tabBarIcon:({tintColor})=>(
<Icon name="ios-document" color={tintColor} size={24} />
)
}
},
},{
tabBarOptions:{
activeTintColor:'#db0202',
inactiveTintColor:'grey',
style:{
fontSize:3,
height:45,
backgroundColor:'white',
borderTopWidth:0,
elevation: 5
}
}
});
export default createAppContainer(TabNavigator);
// home.js
import React from 'react';
import { Font } from 'expo';
import { Button, View, Text, SafeAreaView, ActivityIndicator, ListView, StyleSheet, Image, Dimensions,
ScrollView } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation'; // Version can be specified in package.json
import Icon from 'react-native-vector-icons/Ionicons'
import Courses from './Courses'
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
const { navigate } = this.props.navigation;
return (
<SafeAreaView style={styles.MainContainer}>
<ScrollView
>
<ListView
dataSource={this.state.dataSource}
renderSeparator={this.ListViewItemSeparator}
renderRow={rowData => (
<>
<Text
onPress={() => {
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate("Articles", {
otherParam: rowData.article_title,
});
}}
>
{rowData.article_title}
</Text>
</>
)}
/>
</ScrollView
>
</SafeAreaView>
);
}
}
class ArticleScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions }) => {
const { params } = navigation.state;
return {
title: params ? params.otherParam : '',
};
};
render() {
const { params } = this.props.navigation.state;
const article_title = params ? params.otherParam : '';
return (
<Text>{article_title}</Text>
);
}
}
const RootStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Courses: {
screen: Courses,
navigationOptions: {
header: null,
}
},
Articles: {
screen: ArticleScreen,
},
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
You have to make StackNavigator as main Navigator and TabBar as a sub navigator:
const TabBar = createBottomTabNavigator(RouteConfigs, TabNavigatorConfig);
const MainNavigator = createStackNavigator(
{
TabBar,
WelcomeScene: { screen:Scenes.WelcomeScene },
HomeScene: { screen: HomeScene }
}
Using this when you go the second screen Tabbar will hide automatically.
Can you try this?
class ArticleScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: params ? params.otherParam : '',
tabBarVisible: false
};
};
...
How about something like this. Create Tab navigator and pass it down to Stack navigator as one of the screen, when you navigate to the Articles, it will hide the tab bar...
const TabNavigator = createBottomTabNavigator({
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: 'Главная',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-home" color={tintColor} size={24} />
),
},
},
Courses: {
screen: Courses,
navigationOptions: {
tabBarLabel: 'Courses',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-school" color={tintColor} size={24} />
),
},
},
Editor: {
screen: Editor,
navigationOptions: {
tabBarLabel: 'Editor',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-document" color={tintColor} size={24} />
),
},
},
}, {
tabBarOptions: {
activeTintColor: '#db0202',
inactiveTintColor: 'grey',
style: {
fontSize: 3,
height: 45,
backgroundColor: 'white',
borderTopWidth: 0,
elevation: 5,
},
},
});
const stackNavigator = createStackNavigator({
Home: {
screen: TabNavigator,
navigationOptions: {
header: null,
},
},
Articles: {
screen: ArticleScreen,
},
// add screens here which you want to hide the tab bar
});
export default createAppContainer(stackNavigator);

Is there a way to hide a tab item when using createBottomTabNavigator and createStackNavigator and at the same time navigationOptions working?

I have three screens, i want to use the te tab bar only for the firsts two screens. In those two screens i put a button that navigate to the third screen.
my first aproach was tis code:
import React from "react";
import { Platform } from "react-native";
import {
createStackNavigator,
createBottomTabNavigator,
StackViewTransitionConfigs
} from "react-navigation";
import TabBarIcon from "../components/TabBarIcon";
import HomeScreen from "../screens/HomeScreen";
import LinksScreen from "../screens/LinksScreen";
import SettingsScreen from "../screens/SettingsScreen";
const Tabs = createBottomTabNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
tabBarLabel: "Home",
title: "Tahiry",
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === "ios"
? `ios-information-circle${focused ? "" : "-outline"}`
: "md-information-circle"
}
/>
)
})
},
Links: {
screen: LinksScreen,
navigationOptions: ({ navigation }) => ({
tabBarLabel: "Links",
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === "ios" ? "ios-link" : "md-link"}
/>
)
})
}
});
export default createStackNavigator({
tabs: Tabs,
Settings: SettingsScreen
});
It is working but the "navigationOptions" are not working, so if i set a title to the header ( that is always displayed even if i set "header:null"), it doesn't appear.
I tried another approach with the next code but i can no manage to hide the third tab item:
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import HomeScreen from '../screens/HomeScreen';
import LinksScreen from '../screens/LinksScreen';
import SettingsScreen from '../screens/SettingsScreen';
const HomeStack = createStackNavigator({
Home: HomeScreen,
});
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-information-circle${focused ? '' : '-outline'}`
: 'md-information-circle'
}
/>
),
};
const LinksStack = createStackNavigator({
Links: LinksScreen,
});
LinksStack.navigationOptions = {
tabBarLabel: 'Links',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-link' : 'md-link'}
/>
),
};
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
});
SettingsStack.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-options' : 'md-options'}
/>
),
};
export default createBottomTabNavigator({
HomeStack,
LinksStack,
SettingsStack,
});
Any advice is welcome.
Use defaultNavigationOptions for customizing your tabBar
defaultNavigationOptions: ({ navigation }) => ({
// You can return any component that you like here!
return <View>
<View>
<Text> Tab 1</Text>
</View>
<View>
<Text> Tab =2</Text>
</View>
</View>
},
}),
If you're trying to hide the tab inside the StackNavigator, you can try this
const HomeTab = createStackNavigator({
Home:{screen: HomeScreen,},
Settings:{screen: SettingsScreen,}
}, {initialRouteName: 'Home', headerMode: 'none')}
HomeTab.navigationOptions = ({navigation}) => {
let tabBarVisible = true;
if(navigation.state.index > 0){
tabBarVisible = false;
}
return {
tabBarVisible,
}
}
const TabNavi = createBottomTabNavigator({
Home:{screen: HomeTab,},
Links :{screen: LinksScreen,},
})
export default TabNavi;
I finally manage to make it working. The solution is from the second approach.
First you have to declare you sceens in the stacks like this:
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details1: DetailsScreen
});
Afterwards you have to import the tabBarIcon separately, i think its is necessary because the createStackNavigator has no TabBarIcon method
import TabBarIcon from "../components/TabBarIcon";
You have now navigations and icons working, you can add as many screens as you want in the stacks. and you only create tabs for the stacks.
Here is the complete example:
import React from "react";
import {
Platform,
StatusBar,
StyleSheet,
View,
Button,
Text
} from "react-native";
import {
createBottomTabNavigator,
createStackNavigator,
createAppContainer
} from "react-navigation";
import TabBarIcon from "../components/TabBarIcon";
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Details1!</Text>
</View>
);
}
}
class DetailsScreen2 extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Details2!</Text>
</View>
);
}
}
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Home!</Text>
<Button
title="Go to Details1"
onPress={() => this.props.navigation.navigate("Details1")}
/>
</View>
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Settings!</Text>
<Button
title="Go to Details2"
onPress={() => this.props.navigation.navigate("Details2")}
/>
</View>
);
}
}
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details1: DetailsScreen
});
HomeStack.navigationOptions = {
tabBarLabel: "Home",
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === "ios"
? `ios-information-circle${focused ? "" : "-outline"}`
: "md-information-circle"
}
/>
)
};
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
Details2: DetailsScreen2
});
SettingsStack.navigationOptions = {
tabBarLabel: "Maison",
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === "ios"
? `ios-information-circle${focused ? "" : "-outline"}`
: "md-information-circle"
}
/>
)
};
export default createAppContainer(
createBottomTabNavigator(
{
Home: HomeStack,
Settings: SettingsStack
},
{
/* Other configuration remains unchanged */
}
)
);
and this is the content of tabBaricon.js
import React from 'react';
import { Icon } from 'expo';
import Colors from '../constants/Colors';
export default class TabBarIcon extends React.Component {
render() {
return (
<Icon.Ionicons
name={this.props.name}
size={26}
style={{ marginBottom: -3 }}
color={this.props.focused ? Colors.tabIconSelected : Colors.tabIconDefault}
/>
);
}
}

React Navigation(V3):How to set navigation function in custom router file?

I have a Router.js to set all of my components with react-navigation.
When I click the component FloorScreen headerRight button will show click alert.
Now I want to change it like this.props.navigation.navigate.goBack();
Router.js:
import React, { Component } from 'react';
import { Image, TouchableOpacity } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
// and import some screen...
const Router = createStackNavigator({
WelcomeScreen: {
screen: WelcomeScreen,
navigationOptions: () => ({
header: null
}),
},
HomeScreen: {
screen: HomeScreen
},
FloorScreen: {
screen: FloorScreen,
navigationOptions: {
drawerLabel: 'test',
headerStyle: {
backgroundColor: commonColor.appBackgroundColor,
},
headerRight: (
<TouchableOpacity onPress={() => alert('click')}>
<Image style={{ width: 20, height: 20}} source={BackIcon} />
</TouchableOpacity>
)
}
}
},
{
initialRouteName: 'WelcomeScreen',
headerMode: 'screen'
});
export default createAppContainer(Router);
I know I can set the code in FloorScreen.js to achieve it:
static navigationOptions = ({ navigation }) => ({
headerRight : (
<TouchableOpacity onPress={() => { navigation.goBack() }}>
<Image />
</TouchableOpacity>
),
});
Is possible to set the code in my Router.js ? Or set the code in FloorScreen.js is the only way to do it ?
Any help would be appreciated.
You can implement it at navigationOption
navigationOptions: () => ({
tabBarLabel: strings.labelJobs,
tabBarIcon: ({ tintColor }) => (
<Icon type="FontAwesome" name="someName" />
),
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (navigation.state.index > 0) {
navigation.dispatch(StackActions.popToTop());
}
defaultHandler();
}
})
The above is to demonstrate how to display first screen of stack, just to show you how you can access navigation within navigationOptions

In React Native how to navigate between screens?

I am using React Navigation. I need to navigate from screen1 to screen2. I created tab navigation which include some screens but not screen1. When I click on a button from screen1 to go to screen2 which should show in tabbed screen, it is showing me error.
This is screen1(Main.js)
import React, { Component } from 'react';
import {
ImageBackground,
StyleSheet,
Text,
View,
Modal
} from 'react-native';
import { Container, Header, Left, Content, Footer, FooterTab, Icon, Grid, Row, Button } from 'native-base';
import TabNav from '../screens/Dashboard';
import { Dashboard } from '../screens/Dashboard';
export default class Main extends Component<{}> {
render() {
return (
<Container>
<Grid>
<Row size={2}>
<View style={{alignItems: 'center', flexDirection: 'column', flex: 1, justifyContent: 'space-around' }}>
<View style={{flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
<Button style={styles.buttonBrowseStyle} onPress={() => this.props.navigation.navigate('Dashboard')}>
<Text>Browse</Text>
</Button>
</View>
</View>
</Row>
</Grid>
</Container>
);
}
}
This is screen2(Dashboard.js)
import React from 'react';
import { Text } from 'react-native';
import { TabNavigator, TabBarBottom } from 'react-navigation';
import Post from './Post';
export const Dashboard = () => {
return (<Text>Dashboard</Text>);
}
const TabNav = TabNavigator ({
Dashboard: {
screen: Dashboard,
},
Post: {
screen: Post,
},
},
{
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: true,
activeBackgroundColor: 'yellow',
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
tabBarIcon: ({focused, tintColor}) => {
const { routeName } = navigation.state;
let iconName;
if(routeName==='Main'){
}
}
}
);
export default TabNav;
Getting this error on clicking "Browse" button.
As the above answer mentioned, you are not including Main Component to your navigation so, you can basically think like they are not connected each other whatsoever.
What I suggest you is having a PrimaryNavigator, you can think as Main component in your case.
const PrimaryNavigator = StackNavigator({
SignInStack: {
screen: SignInStackNavigator
},
SignUpStack: {
screen: SignUpStackNavigator
},
DrawerMainStack: {
screen: MenuDrawerStack
}
},
{
headerMode: 'none'
});
Next step, you can use your TabNavigator as in the below.
const MenuDrawerStack = StackNavigator({
DrawerBar: {
screen: DrawerBar
}
}, {
style: {
leftDrawerWidth: 40
},
index: 0,
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: '#1874CD' },
gesturesEnabled: false,
headerLeft: <Icon
name="menu"
onPress={() => {
navigation.navigate({
key: null,
index: 0,
action: [
navigation.navigate('DrawerToggle')
]
})
}}
/>
}),
})
And finally, you can build your tab navigator :
const DrawerBar = DrawerNavigator({
Shop: {
screen: ShopTabNavigator
},
}, {
drawerPosition: 'left',
headerMode: 'none',
initialRouteName: 'Shop',
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: 'white' },
}),
contentComponent: props => <CustomDrawerMenu {...props} />,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle'
})
You should customize these but what I wanted to show you is that the methodology for navigation in React Native with react-navigation is pretty much like I showed you above.
And as the last part you have to pass PrimaryNavigator to your application as High Order Component.
export default class Main extends Component<{}> {
render() {
return (
<PrimaryNavigator />
);
}
}
Main should be part of StackNavigator. Navigation props is not available in Main because it is not a screen in any of the Navigator configuration.