Navigation in React Native going to wrong page - react-native

I am using react-native: 0.61.4.
In app.js I have
import React from 'react';
import { View, Text } from 'react-native';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import HomeScreen from './pages';
import ProfileScreen from './pages';
const MainNavigator = createStackNavigator({
Home: {screen: HomeScreen},
Profile: {screen: ProfileScreen}
});
const App = createAppContainer(MainNavigator);
export default App;
in pages.js I have
import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Main Page',
};
render() {
const {navigate} = this.props.navigation;
return (
<View style={{flex: 1}}>
<Text>You are on the main Page</Text>
<Button
title="Go to Profile"
onPress={() => navigate('Profile')}
/>
</View>
);
}
}
class ProfileScreen extends React.Component {
static navigationOptions = {
title: 'Profile',
};
render() {
return (
<View style={{flex: 1}}>
<Text>You are on the profile page</Text>
</View>
);
}
}
On the IOS simulator, the app loads properly and shows HomeScreen. When clicking on the button though, instead of taking me to ProfileScreen like it should, it looks like it moves forward in the stack to an identical page of HomeScreen, except the page has a back button that goes back to the actual HomeScreen. Anyone know what is wrong with my navigation?

You are using a default export in your pages.js instead of just export HomeScreen as default switch it to:
export { HomeScreen, ProfileScreen };
So you have access to both in app.js, and import them as
import { HomeScreen, ProfileScreen } from './pages';

Related

How to controll some actions or state outside when using react-navigation?

If I navigate A screen to B screen by react-navigation.
It will generate a Header automatically.
So if I want to add some button deal with like control state or call api on the Header.
I have to add static navigationOptions like this
class B extends Component {
static navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.barTitle}`,
headerBackTitle: null,
headerTintColor: '#fff',
headerRight:
<TouchableOpacity
style={{ flexDirection: 'row', paddingRight: 20 }}
onPress={() => {
callApi();
}}
>
<Text>Call API</Text>
</TouchableOpacity>
});
// other code...
}
But it declare static navigationOptions under class B.
If I set all of my react-navigation settings on another folder:
navigator/index.js
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import RootScreen from '../screens/RootScreen';
import LoginStack from './LoginStack';
import MainStack from './MainStack';
const RootStack = createSwitchNavigator(
{
RootScreen: RootScreen,
LoginStack: LoginStack,
MainStack: MainStack
},
{
initialRouteName: 'RootScreen',
}
)
const AppContainer = createAppContainer(RootStack);
export default AppContainer;
navigator/LoginStack.js
import { createStackNavigator } from 'react-navigation-stack';
import LoginScreen from '../screens/LoginScreen';
import A from '../screens/A';
import B from '../screens/B';
const LoginStack = createStackNavigator(
{
LoginScreen: { screen: LoginScreen },
A: { screen: A },
B: { screen: B }
},
{
initialRouteName: 'LoginScreen',
headerMode: 'none'
}
);
export default LoginStack;
I can't figure it out, how do I achieve that control the state or call api actions on LoginStack.js file ?
Do not consider customization my Header. If I want to use react-navigation Header. Is the only way I have to declare static navigationOptions under class B ?
Your question is not clear enough.
From which file you are trying to call API in LoginStack.js?
By control state, you mean Navigation State or Component State?
What I have understood is you want to call API in each route Screen as API is in the parent file.
You can pass screenProps to call api as shown below.(You can edit the render method to add custom Header)
import React from 'react';
import {View, Text, Button} from 'react-native';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
// Login Stack
import ScreenA from './ScreenA';
import ScreenB from './ScreenB';
const LoginStackRoute = createStackNavigator(
{
ScreenA: ScreenA,
ScreenB: ScreenB
},
{
initialRouteName: 'ScreenA',
headerMode: 'none'
}
);
var LoginStackContainer = createAppContainer(LoginStackRoute);
export default class LoginStack extends React.Component{
alertTest(){
alert('hi')
}
render(){
return(
<>
<View style={{height:50,width:'100%', backgroundColor:'red'}}>
<Text>Custom Header</Text>
</View>
<LoginStackContainer screenProps={{alertTest: ()=>this.alertTest()}}/>
</>
)
}
}
ScreenA or ScreenB can access the API in route file as
import React from 'react';
import {View, Text, Button} from 'react-native';
export default class ScreenA extends React.Component{
render(){
return(
<View>
<Text>This is Screen A</Text>
<Button
title='alert'
onPress={()=>{this.props.screenProps.alertTest()}}
></Button>
</View>
)
}
}

I need to create a DrawerNavigator and the drawer should be available on one screen, not all. So, how do I go about implementing it?

So, I have got a dummy Register activity. When the user presses on TouchableOpacity, the user should be taken to a PortalListScreen which has DrawerNavigator available i.e. a drawer should be available and it needs to be toggled using a hamburger menu. I don't need the drawer on Register screen, only on PortalListScreen and subsequent screens.
I've tried everything but haven't been able to make it work.
App.js:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow
*/
import React, {Component} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
} from 'react-native';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import{
createStackNavigator,
createAppContainer
} from 'react-navigation';
import Login from './components/Login';
import Register from './components/Register';
import Portal from './components/Portal';
const AppNavigator = createStackNavigator(
{
Login:
{
screen: Login
},
Register:
{
screen: Register
},
Portal:
{
screen: Portal
}
},
{
initialRouteName: 'Register'
}
);
const AppContainer = createAppContainer(AppNavigator);
export default class App extends Component{
render()
{
return(
<AppContainer/>
);
}
}
Register.js:
export default class Register extends Component{
render()
{
return(
<View>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Portal')}>
<Text>Go to portal</Text>
</TouchableOpacity>
<Text>This is registration</Text>
</View>
);
}
}
Portal.js:
import React, {Component} from 'react';
import {
View,
Text,
TextInput
} from 'react-native';
import{
createDrawerNavigator,
createAppContainer
} from 'react-navigation';
import Icon from 'react-native-vector-icons/Ionicons';
import PortalListScreen from './PortalListScreen';
const PortalStackNavigator = createStackNavigator(
{
PortalStackNavigator: PortalListScreen
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
}
);
const PortalDrawer = createDrawerNavigator(
{
PortalListScreen:
{
screen: PortalStackNavigator
},
},
{
initialRouteName: 'PortalListScreen'
}
);
const PortalContainer = createAppContainer(PortalDrawer);
export default class Portal extends Component{
render()
{
return(
<PortalContainer/>
);
}
}
PortalListScreen.js:
import React, {Component} from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity
} from 'react-native';
export default class PortalListScreen extends Component{
render()
{
return(
<View>
<TouchableOpacity
onPress={() => this.props.navigation.toggleDrawer}>
<Text>Toggle drawer</Text>
</TouchableOpacity>
<Text>This is PortalListScreen</Text>
</View>
);
}
}
Earlier by clicking on Toggle drawer, nothing was happening but now it has started giving me this error message: Module AppRegistry is not a registered callable module (calling runApplication).
You need to add your Drawer Navigator to AppNavigator in App.js
const AppNavigator = createStackNavigator(
{
Login:
{
screen: Login
},
Register:
{
screen: Register
},
PortalDrawer,
},
{
initialRouteName: 'Register'
}
);

undefined is not an object (evaluating '_this.props.navigation.navigate') upon button click

I am fairly new to react-native and react-navigation and trying to move from one screen to another via button click, keep getting this error. I've found similar questions here on SO (this and this) but they don't work for me, keep getting this error.
What I am doing is, I have an App.js that is the initial screen which for now shows a login form (called Splash):
import React from 'react';
import {
View,
ActivityIndicator,
StyleSheet
} from 'react-native';
import { createDrawerNavigator, createAppContainer } from "react-navigation";
import HomeScreen from './HomeScreen';
import ProfileScreen from './ProfileScreen';
import Splash from './Splash';
export default class App extends React.Component {
render() {
const { navigation } = this.props;
return (
<View>
<Splash navigation={navigation}/>
</View>
);
}
}
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
}
}, {
initialRouteName: "Home",
contentOptions: {
activeTintColor: '#e91e63'
}
});
const AppContainer = createAppContainer(AppNavigator);
On my Splash screen I now have no functionality as I am just trying to get it to move to my HomeScreen when I hit the Login button:
import React, { Component } from 'react';
import {
ScrollView,
Text,
TextInput,
TouchableOpacity,
StyleSheet
} from 'react-native';
class Splash extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ScrollView style={{padding: 20}}>
<TextInput autoCapitalize="none"
onSubmitEditing={() => this.passwordInput.focus()}
autoCorrect={false}
keyboardType='email-address'
returnKeyType="next"
placeholder='Email address'
placeholderTextColor='rgba(225,225,225,0.7)'/>
<TextInput returnKeyType="go"
ref={(input)=> this.passwordInput = input}
placeholder='Password'
placeholderTextColor='rgba(225,225,225,0.7)'
secureTextEntry/>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Home')}>
<Text>LOGIN</Text>
</TouchableOpacity>
</ScrollView>
)
}
};
export default Splash;
What happens now is that as soon as I hit the login button, I get the error in the title. Any clues on what I am doing wrong?
Remove App component, you don't need it in this case. Make Splash as your initial screen
const AppNavigator = createDrawerNavigator({
Splash: {
screen: Splash
},
Home: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
}
}, {
initialRouteName: "Splash",
contentOptions: {
activeTintColor: '#e91e63'
}
});
then export AppContainer directly
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer

Confusion with react-navigation with react-navigator 3

I am using react-navigation v3 for navigation in my react-native app. When I start app, It navigates to final navigation page i.e. Electonics
AppNavigator.js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import Home from '../container/Home';
import BooksScreen from '../container/BooksScreen'
import ElectronicsScreen from '../container/ElectronicsScreen';
const AppNavigator = createStackNavigator({
Home:Home,
Book: BooksScreen,
Electronics: ElectronicsScreen
});
export default AppContainer = createAppContainer(AppNavigator);
Home.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity as Button } from 'react-native';
export default class Home extends Component {
render() {
return (
<View>
<Text> Home Page </Text>
<Button
title="Books"
onPress={this.props.navigation.navigate('Book')}
>
</Button>
<Button
title="Books"
onPress={this.props.navigation.navigate('Electronics')}
>
</Button>
</View>
);
}
}
App.js
import AppContainer from './src/Navigation/AppNavigator';
export default class App extends Component {
render() {
console.log(this.props)
return (
<AppContainer />
);
}
}
When I run the code, it runs directly to the ElectronisScreen.js. How can I make it stay at the Home?
Change your AppNavigator to below.
const AppNavigator = createStackNavigator({
Home: Home,
Book: BooksScreen,
Electronics: ElectronicsScreen
},
{
initialRouteName: 'Home',
});
you have to define your initialRouteName.

React Native Navigation : Child components are not rendered on screen

I followed the documentation here and wrote this code.
App.js
import React from "react";
import {createAppContainer, createStackNavigator} from 'react-navigation';
import LoginScreen from "./src/components/LoginScreen";
export default App = () => createAppContainer(createStackNavigator({
Login: {screen: LoginScreen},
}));
LoginScreen.js
import React, {Component} from 'react';
import {View, Text, Button} from 'react-native';
export default class LoginScreen extends Component {
static navigationOptions = {
title: 'Login',
};
render() {
const {navigate} = this.props.navigation;
return (
<View style={this.styles.viewStyle}>
<Text> Login </Text>
<Button
title="Go to Jane's profile"
onPress={() => navigate('Home', {name: 'Jane'})}
/>
</View>
);
}
}
Output
A blank screen. Login page is not rendered on screen.
You are trying to export a method in your App.js
Either Import and use it as a method or change your default export to
export default App = createAppContainer(createStackNavigator({
Login: {screen: LoginScreen},
}));