I am creating an app using React Native, Expo and React Navigation, and I don't know the correct method for passing props and functions around.
I have copied the Expo method for navigators that I will build on, but right now I just have App.js calling the following AppNavigator -> MainSwitchNavigator -> HomeScreen
I have then wrapped the main exported App that Expo expects with the Amazon AWS Amplify HOC withAuthenticator. Now I can log in to my app and show hello world securely using Amazon's cognito service.
If I want to log out I can use the signout function bellow that I currently have on the props of App.
class App extends React.Component {
constructor(props) {
super(props);
this.signOut = this.signOut.bind(this);
}
signOut() {
Auth.signOut().then(() => {
this.props.onStateChange('signedOut', null);
console.log("signed out");
}).catch(e => {
console.log(e);
});
}
render () {
return (
<View style={styles.container}>
<AppNavigator screenProps={{
signOut: () => {this.signOut}
}}/>
</View>
);
}
}
export default withAuthenticator(App)
For now I just want to pass this function down to my Home Screen so I can add a button and log out.
AppNavigator
export default createAppContainer(
createSwitchNavigator({
// You could add another route here for authentication.
// Read more at https://reactnavigation.org/docs/en/auth-flow.html
Main: { screen: MainSwitchNavigator, params: { signOut: this.props.screenProps.signOut } },
},
{
initialRouteName: 'Main'
})
);
MainSwitchNavigator
export default createSwitchNavigator({
// Home: { screen: HomeScreen }
Home: { screen: HomeScreen, params: { signOut: this.props.navigation.params.signOut } }
},{
initialRouteName: 'Home'
});
HomeScreen
class HomeScreen extends Component {
render () {
return (
<View>
<Text>Main App Here</Text>
<Button
onPress={this.props.navigation.params.signOut()}
title="Sign Out"
/>
</View>
)};
}
export default HomeScreen;
At the moment I get the error
undefined is not an object (evaluating 'this.props.navigation')
<unknown>
MainSwitchNavigator.js
8:62
Which puts its at the point I'm trying to read the props passed in to MainSwitchNavigator.
So my question is, what is good practice on sharing functions and state with screens below the main App and how do I pass the signOut function down to the rest of my components?
=======================================================================
EDIT
I have since worked out how to use screenProps correctly for variables but not for functions. screenProps is passed down through navigators automatically to the screen. So I only have to pass it to the AppNavigator component once and I can access it in HomeScreen. However any functions are not passed down.
E.g for variables, if I modify App.js to pass text to the variable signOut and pass that to screenProps
class App extends React.Component {
constructor(props) {
super(props);
this.signOut = this.signOut.bind(this);
}
signOut() {
Auth.signOut().then(() => {
this.props.onStateChange('signedOut', null);
console.log("signed out");
}).catch(e => {
console.log(e);
});
}
render () {
return (
<View style={styles.container}>
<AppNavigator screenProps={{signOut: "some text"}}/>
</View>
);
}
}
HomeScreen will then show this as part of the this.props object.
class HomeScreen extends Component {
render () {
return (
<View>
<Text>Main App Here</Text>
<Button
onPress={console.log(JSON.stringify(this.props))}
// onPress={alert(this.props.screenProps.var3)}
title="Sign Out"
/>
</View>
)};
}
export default HomeScreen;
However if I pass a function to AppNavigator instead and do this
<AppNavigator screenProps={{signOut: () => {this.signOut}}}/>
screenProps does not get set and I can't access the function signOut. The only thing I can get to work is this
<AppNavigator screenProps={this.signOut}/>
But what I need is to create a property of screenProps and pass this down. Any thoughts?