How do i switch screens from one file to another - react-native

I'm very new to react native so please explain carefully.i have 3 files App.js SplashAndLogin.js and Register.js Im able to get from the initial screen to the register screen and go back and forth between my components in my Register file but when its time to go back to the Login screen i always seem to get the same error.
I've tried several different things but they all keep giving me the same error. im starting to think the way i set up my files are just wrong.
//App.js
class App extends Component<Props> {
render() {
return (
<AppContainer/>
)
}
}
export default App
const AppSwitchNavigator = createSwitchNavigator(
{
Login: {screen: SplashAndLogin},
//Registe :{screen: Register}
});
//SplashAndLogin.js
class SplashAndLogin extends Component<Props> {
render() {
return (
<AppContainer/>
)
}
}
export default SplashAndLogin;
const SAndLAppNavigator = createSwitchNavigator(
{
SandL : {screen: LoadingScreen },
RegisterScreen : {screen: Register}
}
);
//Register.js
export default class Application extends Component<Props> {
render() {
return (
<AppContainer/>
);
}
}
const AppSwitchNavigator = createStackNavigator(
{
Login :{screen: NameScreen},
PhoneAndEmail: {screen: EmailPasswordScreen},
HomeScreen: {screen: SplashAndLogin },
UploadScreen: {screen: CertificateUploadScreen }
});
const AppContainer = createAppContainer(AppSwitchNavigator);
So to summarize i can get to every screen except when im on the Register.js file and try to navigate to the HomeScreen it throws out the error
"The component for route 'HomeScreen' must be a react component For example...."

It's normal, you are using two different AppContainer.
You can not call a view in another AppContainer from the current AppContainer
this.props.navigation
refers to the current navigation

Use the state to change AppContainer
class RenderAppContainer extends Component {
constructor(props) {
super(props);
this.state = { IsConnected : false }
this.changeIsConnected = this.changeIsConnected.bind(this)
}
changeIsConnected = () => {
this.setState((prevState, props ) => ({ IsConnected : !prevState.IsConnected}))
}
render() {
cons {IsConnected } = this.state
return(
<React.Fragment>
{(IsConnected) ? AppContainerOne : AppContainerTwo } 
</React.Fragment
)
}
}
You can then pass changeIsConnected to your AppContainer
<AppContainerOne screenProps={{changeConnected: this.changeIsConnected}} />
<AppContainerTwo screenProps={{changeConnected: this.changeIsConnected}} />
https://reactnavigation.org/docs/en/stack-navigator.html
see documentation for ScreenProps

Related

How to pass props to react navigation in react native app

I am using HOC to get current user details on login for each route in my react native application using ApolloClient.
Below is my main component App.tsx:
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { createStackNavigator } from 'react-navigation-stack';
const client = new ApolloClient({
cache,
link: errorLink.concat(authLink.concat(httpLink))
});
const TabStack = createBottomTabNavigator({
Feed: {
screen: Feed
},
Upload: {
screen: Upload
},
Profile: {
screen: Profile
}
})
const MainStack = createStackNavigator(
{
Home: { screen: TabStack },
User: { screen: UserProfile },
Comments: { screen: Comments },
Post: { screen: Post }
},
{
initialRouteName: 'Home',
mode: 'modal',
headerMode: 'none'
}
)
const AppContainer = createAppContainer(MainStack);
//Here I assign HOC to AppContainer
const RootWithSession = withSession(AppContainer);
class App extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (<ApolloProvider client={client}>
<RootWithSession/>
</ApolloProvider>)
}
}
export default App;
Below is HOC withSession.tsx:
export const withSession = Component=>props=>(
<Query query={GET_CURRENT_USER}>
{({data,loading,refetch})=>{
if (loading) {
return null;
}
console.log(data);
return <Component {...props} refetch={refetch}/>;
}}
</Query>
)
I want to pass refetch function to all the components
<Component {...props} refetch={refetch}/>
How to do this? Any help is greatly appreciated.
I was able to pass refetch function to all Components from HOC withSession component using ScreenProps of StackNavigator as below:
export const withSession = Component=>props=>(
<Query query={GET_CURRENT_USER}>
{({data,loading,refetch})=>{
if (loading) {
return null;
}
if(props && props.navigation){
//props.refetch = refetch;
console.log(props)
//props.navigation.refetch = refetch;
props.navigation.setParams({refetch});
}
return <Component screenProps={{refetch}} {...props} refetch={refetch}/>;
}}
</Query>
)
Now, I am able to get refetch method using this.props.screenProps.refetch

How to pass login credentials to initial screen of DrawerMenu of navigation drawer in React Native?

I have created React-navigation Drawer V3 in my app. I am facing the problem of getting the login credentials on the initial screen that is the "Home" screen of my drawer navigation stack. Although I am passing the data on DrawerMenu.js from Login.js with the help of :
this.props.navigation.navigate('DrawerMenu', {
loginData: loginData
})
and getting the data on DrawerMenu.js with :
constructor(props) {
super(props)
this.state = {
loginData: props.navigation.state.params.loginData
}
}
But I need to get this data to Home.js which I am not able to get. The reason of getting the data to DrawerMenu.js was because there are several other screens in the stack which want the logindata and they are able to get it using screenProps used in drawer content component but as Home is the initial screen so there no way that it receives the data on the first time, only the DrawerMenu.js file receives it initially. Can someone help me out on this?
Here is my code of DrawerMenu with navigation stack.
class DrawerMenu extends Component {
constructor(props) {
super(props)
this.state = {
loginData: props.navigation.state.params.loginData
}
}
static navigationOptions =
{
header: null,
};
render() {
return (
<SafeAreaView style={styles.droidSafeArea}>
<MyApp screenProps={{ loginData: this.state.loginData}} />
</SafeAreaView>
)
}
}
class Hidden extends React.Component {
render() {
return null;
}
}
const MainScreenNavigator = createStackNavigator({
Home: { screen: Home },
Screen1: {
screen: Screen1
},
Screen2: {
screen: Screen2
},
Screen3: {
screen: Screen3
}
},
{
initialRouteName: 'Home',
});
const MyDrawerNavigator = createDrawerNavigator(
{
Main: {
screen: MainScreenNavigator,
navigationOptions: {
drawerLabel: <Hidden />
}
}
},
{
drawerWidth: 300,
contentComponent: DrawerComponent
});
const MyApp = createAppContainer(MyDrawerNavigator);
export default DrawerMenu;
I am using :
"react-native" : "0.57.5",
"react": "16.6.1",
"react-navigation": "^3.5.1"
You can use AsyncStorage to save the data
To store
_storeData = async () => {
try {
await AsyncStorage.setItem('Key Value', 'Item Value');
} catch (error) {
// Error saving data
}
};
To retrieve
_retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('Key Value');
if (value !== null) {
// We have data!!
console.log(value);
}
} catch (error) {
// Error retrieving data
}
};
Or you can use redux.

Share params state between stack navigators in react-navigation

How do I share params from a stack navigator to several stack navigators nested within a tab navigator?
const UsersStack = createStackNavigator(...)
const PostsStack = createStackNavigator(...)
const AlbumsStack = createStackNavigator(...)
const ToDosStack = createStackNavigator(...)
const MainTabNavigator = createBottomTabNavigator({
PostsStack,
AlbumsStack,
ToDosStack
});
const AppNavigator = createAppContainer(
createSwitchNavigator({
User: UsersStack,
Main: MainTabNavigator
})
);
From the UsersScreen within the UsersStack, I'm using..
navigation.navigate("Main", { userId: "1" })
Arrives at PostsScreen within PostsStack with no params
navigation.navigate("Posts", { userId: "1" })
Arrives at PostsScreen within PostsStack with params available, but only on the PostsStack. Switching tabs to either AlbumsStack or ToDosStack shows no params available.
Expected output is to have userId params available on all stacks.
The best way is to use Context API. Create context and hold your userid then wrap Stack Navigation component inside Context.Provider
import NavigationContext from './components/MyContext'
export default class App extends React.Component {
render() {
return (
<NavigationContext.Provider value={{
"userId": "1"
}}>
<AppNavigator />
</NavigationContext.Provider>
);
}
}
Now to consume userId use Context.Consumer that will receives the current context value and returns it to all stacknavigator screens
import React from 'react'
import { View, Text, Button, StyleSheet } from 'react-native';
import NavigationContext from './MyContext'
export default class UserScreen extends React.Component {
constructor(props) {
super(props)
}
_navigate = () => {
this.props.navigation.navigate('Page2')
}
render() {
return (
<NavigationContext.Consumer>
{
({ userId }) => {
return (
<View style={styles.container}>
<Text>Page 1</Text>
<Text>{`UserId ${userId}`}</Text>
<Button onPress={this._navigate} title="Navigate to page 2" />
</View>)
}
}
</NavigationContext.Consumer>
)
}
}
See example from here https://snack.expo.io/#selvaganesh93/navigationglobalcontextdemo

React native navigation from seperated class files

I'm just started learning React Native. Used create-react-native-app. Code works as well. I can navigate my screen to Details from HomeScreen.
App.js file:
class HomeScreen extends React.Component {
render() {
_onPressButton() {
this.props.navigation.navigate('DetailsScreen');
}
return (
// Views
);
}
}
class DetailsScreen extends React.Component {
render() {
return (
// Views
);
}
}
const RootStack = StackNavigator(
{
HomeScreen: { screen: HomeScreen, },
DetailsScreen: { screen: DetailsScreen, },
},
{ initialRouteName: 'HomeScreen', }
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
Then i separated HomeScreen and DetailScreen into individual js file from App.js file. And now i am unable to navigate them. What makes it unable to navigate them?
App.js file:
import ...
import HomeScreen from './screens/homeScreen';
import DetailsScreen from './screens/detailsScreen';
const RootStack = StackNavigator(
{
HomeScreen: {screen: HomeScreen,},
DetailsScreen: {screen: DetailsScreen,}
},
{ initialRouteName: 'HomeScreen', }
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
HomeScreen.js file
import ...
export default class HomeScreen extends React.Component {
_onPressButton() {
Alert.alert('You tapped the button!');
this.props.navigation.navigate('DetailScreen');
}
render() {
return (
// View
);
}
}

How to send parameters from screen to stack navigator?

I am a newbie to react native.
I am using a stack navigator inside a tab navigator; I have to navigate multiple screens inside each tab. i am able to send parameters from my default class HomePage to my nested classes in my tab and stack navigators.
export const MyApp = TabNavigator({
Asset: {
screen: AssetScreen,
},
Sensors: {
screen: sensorsStack,
},
Settings: {
screen: settingStack
},
}
export const sensorsStack = StackNavigator({
sensors : { screen: SensorScreen },
sensorDetails : { screen: SensorDetails }
});
export const settingStack = StackNavigator({
settings: { screen: SettingsScreen },
about : { screen: About },
environment : { screen: Environment }
});
export default class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
assetID:'xyz',
authToken:'xyzz'
}
}
static navigationOptions = {
header: null
};
render() {
const screenProps = {
asset: {
assetID: this.state.assetID,
authToken : this.state.authToken,
},
}
return (
<MyApp screenProps={screenProps} />
);
}
}
Now, i want to send a parameter from 'SensorScreen' to 'SensorDetails'. I have tried sending parameters using
NavigationActions.navigate({ routeName: 'sensorDetails' ,params: { sensorType:'Fuel',}});
from 'SensorScreen' class. But was not able to get the parameter in 'SensorDetails' class. How can i pass this params?
A little late answer but might help others that ends up here.
Instead of using NavigationActions you could try navigation from sensorScreen to sensorDetails with navigate and passing some extra variables.
this.props.navigation.navigate('SensorDetails',{sensorType:'Fuel'})
The passed object can then be read in the second screen by
this.props.navigation.state.params.sensorType
A minimal example of the case can be seen in these lines. Observe that this is a stupid on icon tab bar. But it is kept that way since the question was about a tab bar with stacks on each tab. And new tabs are easily added.
import React,{Component} from 'react'
import { Text, View, Footer,Button } from 'react-native'
import {StackNavigator,TabNavigator} from 'react-navigation'
export class SensorScreen extends React.Component {
render() {
return (<Button
onPress={() => this.props.navigation.navigate('SensorDetails',{sensorType:'Fuel'})}
title="Go to Sensor Details"
/>)}}
export class SensorDetails extends React.Component {
render() {
return (<View>
<Text>{this.props.navigation.state.params.sensorType}</Text>
</View>);}
}
const sensorsStack = StackNavigator({
sensors : { screen: SensorScreen },
SensorDetails : { screen: SensorDetails }
});
const MyApp = TabNavigator({
Sensors: {
screen: sensorsStack,
},
});
export default class Nested extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<MyApp/>
);
}
}
Hope this helps.