I am a new React-native programmer . I am trying to pass params from a StackNavigator to TabNavigator but when I tried to print the params by using this.props.navigation.state.params , it is undefined.
I am trying to pass the user's name from fetch to a new screen
Auth.js
export const onVerify = (email,password,navigation) => {
console.log('Verifying');
fetch('xxx',
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'email=' + email + '&password=' + password
})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.status == '200') {
Alert.alert(
'Login Successful',
'Welcome Home'
);
let data = {
name: responseJson.name,
id : responseJson.id
};
console.log(data.name)
onSignIn().then(() => navigation.navigate("SignedIn"),data);
}
})
.catch((error) => {
console.error(error);
});
}
And here is my router.js
export const SignedOut = StackNavigator({
SignUp: {
screen: SignUp,
navigationOptions: {
title: "Sign Up",
headerStyle
}
},
SignIn: {
screen: SignIn,
navigationOptions: {
title: "Sign In",
headerStyle
}
}
});
export const SignedIn = TabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: "Home",
tabBarIcon: ({ tintColor }) => (
<FontAwesome name="home" size={30} color={tintColor} />
)
}
},
Profile: {
screen: Profile,
navigationOptions: {
tabBarLabel: "Profile",
tabBarIcon: ({ tintColor }) => (
<FontAwesome name="user" size={30} color={tintColor} />
)
}
}
},
{
tabBarOptions: {
style: {
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0
}
}
}
);
Any ideas ?
You are sending params the wrong way,
Old:
onSignIn().then(() => navigation.navigate("SignedIn"),data); //wrong
New:
onSignIn().then(() => navigation.navigate("SignedIn", data)); //correct
From the docs of React-Navigation,
Pass params to a route by putting them in an object as a second
parameter to the navigation.navigate function:
this.props.navigation.navigate('RouteName', { /* params go here */ })
Related
I have been reading a lot of answers on SO as well as GitHub issues trying to implement a solution, but have been unable to come up with a solution for this situation.
Here is a representation of my code:
class MeetingsScreen extends React.Component {
constructor(props) {
super(props)
this.state = {
upcomingMeeting: [],
refreshing: false
};
}
async handlePress() {
const user = await AsyncStorage.getItem('User');
this.props.navigation.navigate('WriteSummary', { id: user.id, type: 'submit' });
}
printUpcomingMeetings = () => {
return (<View style={styles.meeting}>
<Button
containerStyle={styles.meetingButton}
style={styles.meetingButtonText}
onPress={() => this.handlePress(user.id)}
Press me to write summary!
</Button>
</View>);
}
}
render () {
return (<View style={{flex:1}} key={this.state.refreshing}>
{ this.printUpcomingMeetings() }
</View>);
}
}
class WriteSummaryScreen extends React.Component {
constructor(props) {
super(props)
this.state = {
storageId: '',
normalId: -1,
type: '',
curSummary: ''
}
}
componentDidMount = () => {
const { params } = this.props.navigation.state;
const { id, type } = params ? params : null;
const storageId = 'summary_' + id;
this.setState({storageId:storageId});
this.setState({normalId:id});
this.setState({type:type});
AsyncStorage.getItem(storageId).then((value) => this.setSkipValue(value));
}
async setSkipValue (value) {
if (value !== null) {
this.setState({ 'curSummary': value });
} else {
this.setState({ 'curSummary': '' });
}
}
async saveSummary (text) {
this.setState({'curSummary': text});
await AsyncStorage.setItem(this.state.storageId, text);
}
async handleSubmit() {
const user = await AsyncStorage.getItem('User');
if (this.state.type === 'submit') {
// post insert
const postres = fetch (url + '/create-summary', {
method: 'POST',
body: JSON.stringify({
AppointmentId: this.state.normalId,
SummaryText: this.state.curSummary,
UserId: user.Id
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.catch((error) => {
console.error(error);
});
} else {
// post update
const postres = fetch (url + '/update-summary', {
method: 'POST',
body: JSON.stringify({
AppointmentId: this.state.normalId,
SummaryText: this.state.curSummary,
UserId: user.Id
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.catch((error) => {
console.error(error);
});
}
this.props.navigation.navigate('Meetings');
}
render () {
return <View style={{flex:1}}>
<View>
<View style={{height:25, backgroundColor: colors.vikingBlue}}></View>
<View style={{height:30, backgroundColor: colors.white}}></View>
<View style={{flexDirection:'row', backgroundColor: colors.white, alignItems:'center'}}>
<View style={{width:5}}></View>
<TouchableOpacity onPress={() => this.props.navigation.goBack()} activeOpacity={0.5}>
<Image style={{width:30, height:30}} source={require('./assets/icons8-back-50.png')} />
</TouchableOpacity>
<View style={{width:10}}></View>
<View style={{width:mainTitleWidth,textAlign:'center',alignItems:'center'}}>
<Text style={{fontSize:22}}>Settings</Text>
</View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('HelpModal')} activeOpacity={0.5}>
<Image style={{width:30, height:30}} source={require('./assets/help.png')} />
</TouchableOpacity>
</View>
<View style={{height:30, backgroundColor: colors.white}}></View>
</View>
<TextInput
multiline
numberOfLines={6}
style={styles.summaryInput}
onChangeText={text => saveSummary(text)}
value={this.state.curSummary} />
<Button
containerStyle={styles.summaryButton}
style={styles.summaryButtonText}
onPress={this.handleSubmit()}>
Submit
</Button>
</View>
}
}
function HomeStack() {
return (
<Tab.Navigator
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Meetings" component={MeetingsScreen} />
<Tab.Screen name="Topics" component={TopicsScreen} />
</Tab.Navigator>
);
}
export default class AppContainer extends React.Component {
// Main rendering function. Always begins on the SplashScreen, which checks user login status and directs to Meetings. I left it out and the other Tab navigator screens for less clutter.
render() {
return (
<NavigationContainer>
<Stack.Navigator headerMode='none' initialRouteName='Splash'>
<Stack.Screen name='Splash' component={SplashScreen} />
<Stack.Screen name='Main' component={HomeStack} />
<Stack.Screen name='WriteSummary' component={WriteSummaryScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
};
I get the error TypeError: undefined is not an object (evaluating '_this7.props.navigation.state.params)' after pressing the button on MeetingsScreen and navigating to WriteSummaryScreen.
What confuses me is the screen is navigated to, so the data should have been passed. What am I missing?
You can access parametes like below if its class based component:
class WriteSummaryScreen extends React.Component {
const {id, type} = this.props.route.params;
//........
for the functional component:
const WriteSummaryScreen =({navigation, route})=>{
const {id, type} = route.params;
//..........
}
You can access the params that you have passed from a screen using the getParam function.
so you can use this code:
const id = this.props.navigation.getParam("id");
const type = this.props.navigation.getParam("type");
What ended up working for me was the following:
const id = this.props.route.params.id;
const type = this.props.route.params.type;
i'm using react navigation v5,
i'm trying to navigate to login screen from alert when user press Ok,
but currently not working with error >>
can't find variable: navigation
The function is below :
async function handleSubmit(navigation) {
try {
const value = await AsyncStorage.getItem('storage_useremail');
if (value !== null) {
fetch('https://xxxxxx/logout', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: value,
}),
}).then(res => res.json())
.then(res => {
// console.log(res.err_code)
if (res.err_code == '0000') {
Alert.alert('Notice',res.message + " (" + res.err_code + ")",[{ text: 'Yes', onPress: () => navigation.navigate('Login')} ]);
} else {
Alert.alert("Response: " + res.err_code + " - " + res.message);
}
})
}
} catch (error) {
// Error retrieving data
}
}
function HomeNavigator() {
return (
<AppStack.Navigator mode="modal" initialRouteName="Login" screenOptions={({ route, navigation }) => ({
headerStyle: {
backgroundColor: '#fb5b5a',
borderBottomWidth: 0,
},
headerRight: () => (
<Button
onPress={() => handleSubmit()}
// onPress={() => navigation.navigate('Login')}
title="Logout"
color="#fff"
/>
),
})}>
<AppStack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Home',
}}
/>
<AppStack.Screen
name="Memory"
component={MemoryScreen}
options={{
title: 'Memory',
}} />
</AppStack.Navigator>
);
}
navigation.navigate('Login') << this the part where can't navigate.
Can somebody help this?
Thanks before
Because you don't pass navigation to handleSubmit
function HomeNavigator() {
return (
<AppStack.Navigator mode="modal" initialRouteName="Login" screenOptions={({ route, navigation }) => ({
headerStyle: {
backgroundColor: '#fb5b5a',
borderBottomWidth: 0,
},
headerRight: () => (
<Button
onPress={() => handleSubmit(navigation)} // <<<<<<<<<<<< Here
// onPress={() => navigation.navigate('Login')}
title="Logout"
color="#fff"
/>
),
})}>
<AppStack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Home',
}}
/>
<AppStack.Screen
name="Memory"
component={MemoryScreen}
options={{
title: 'Memory',
}} />
</AppStack.Navigator>
);
}
onPress should be a function declaration that will be triggered when pressed
onPress: () => navigation.navigate('Login')
I have 2 screens;
Login screen
Main screen with 2 tabs in it. (createbottomnavigation)
I want to acces my 3rd screen from Main screen, but I got an error: "undefined is not an object..."
Here is my routes in app.js:
const Routes = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: ({ navigation }) => ({
header: null,
}),
},
Main: {
screen: MainScreenRoutes,
navigationOptions: ({navigation}) => ({
header: null,
}),
},
MyProfil: {
screen: MyProfile,
}
},
{
initialRouteName: 'Login',
headerMode: 'screen',
navigationOptions: {
...HeaderStyles,
animationEnabled: true
}
}
);
I can not access MyProfil from "Main" screen where I had my tabs.
Main profile router:
let headerDefaultNavigationConfig = {
header: props => <CustomHeader {...props} />,
...HeaderStyles
};
const Tab1 = createStackNavigator(
{
Domov: {
screen: HomeScreen,
navigationOptions: {
},
},
/*MyProfil: {
screen: MyProfil,
}*/
},
{
navigationOptions: {
...headerDefaultNavigationConfig
}
}
);
const Tab2 = createStackNavigator(
{
Dnevnik: {
screen: Diary,
navigationOptions: {
headerTitle: "Tab2",
headerLeft: (
<Text>Ok</Text>
)
},
}
},
{
navigationOptions: {
...headerDefaultNavigationConfig
}
}
);
const bottomTabs = createBottomTabNavigator(
{
Domov: Tab1,
Dnevnik: Tab2,
},
{
initialRouteName: "Domov",
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Domov') {
//iconName = `home${focused ? '' : '-outline'}`;
iconName='home';
} else if (routeName === 'Dnevnik') {
//iconName = `ios-calendar${focused ? '' : '-outline'}`;
iconName='ios-calendar';
}
// if focused return view with line
if(focused) {
return (
<View style={styles.item}>
<Icon name={iconName} style={{fontSize: 20, color: '#FFF'}} />
<View style={styles.line}></View>
</View>
);
} else {
return(
<Icon name={iconName} style={{fontSize: 20, color: '#FFF'}} />
)
}
},
}),
tabBarPosition: 'bottom',
tabBarOptions: {
activeTintColor: 'white',
showLabel: false,
inactiveTintColor: '#4C2601',
style: {
backgroundColor: '#033D51',
},
labelStyle: {
fontSize: 12,
lineHeight: 30,
},
},
swipeEnabled: true,
});
/*const All = createStackNavigator(
{
"Home":{
screen: bottomTabs,
navigationOptions: {
header: null,
},
},
"MyProfil":{screen: MyProfil},
},
{
initialRouteName: 'Home',
headerMode: 'screen',
navigationOptions: {
...HeaderStyles,
animationEnabled: true
}
}
);
*/
export default bottomTabs;
This is my code to change screen;
const { navigate } = this.props.navigation;
navigate('MyProfil');
This is my current navigation
const MainNavigator = TabNavigator(
{
SignIn: {
screen: SignInScreen,
},
Home: {
screen: SubNavigator,
}
},
{
navigationOptions: {
tabBarVisible: false,
swipeEnabled: false
},
initialRouteName: 'SignIn',
lazy: true
}
);
const SubNavigator = DrawerNavigator(
{
Page1: {
screen: StackNavigator(
{
pageOne: {
screen: ScreenOne,
navigationOptions: ({ navigation }) => ({
title: 'One',
headerLeft: (
<TouchableOpacity onPress={() => navigation.navigate('DrawerOpen')}>
<IOSIcon name="ios-menu" size={30} />
</TouchableOpacity>
),
headerStyle: { paddingRight: 10, paddingLeft: 10 },
})
},
pageTwo: { screen: ScreenTwo },
camera: {
screen: CameraScreen,
navigationOptions: {
title: 'Camera'
}
},
qrscanner: {
screen: QRScanner,
navigationOptions: {
title: 'QR Scanner'
}
},
},
)
},
Profile: {
screen: ProfileScreen, // log out from here
},
},
{
contentComponent: SideMenu,
initialRouteName: 'Driver',
contentOptions: {
activeTintColor: '#e91e63'
}
}
);
I want to log out from Profile and reset it to SignIn. It is triggered by onPress.
Inside code for Profile I put function and render a text like this
/*.......*/
navigateToReset(route) {
const navigateReset = NavigationActions.reset({
index: 0, key: null, actions: [NavigationActions.navigate({ routeName: route })],
});
this.props.navigation.dispatch(navigateReset);
}
onButtonPressSignOut = () => {
this.navigateToReset('SignIn');
}
/*....*/
render () {
return(
<View>
<Text onPress={this.onButtonPressSignOut}>
Sign Out
</Text>
</View>
);
}
But this gave me error:
Error: There is no route defined for key SignIn.
Must be one of: 'pageOne', 'pageTwo', 'camera', 'qrscanner'
I have searched online and found several issue like this.
This is some of the issue I found : Issue1, Issue2 but it does not work for me.
Did I miss something in the above code?
Thank you for your help and suggestion.
I adding image of screen, this work in part of screen.
The Contacts screen need to be main page and not screen1 but its didn't work if i replace between them.
I adding the code, in 'LogedInNavigator' have there TabNavigator and DrawerNavigator - the 'Contants' page initializing from TabNavigator and part two - Screen1 with the side menu it's from DrawerNavigator - maybe it's doing the problem?
LogedInNavigator.js
import.......
styles......
const LoggedInNavigator = TabNavigator(
{
Contacts: {screen: ContactScreen,},
Chat: {screen: ChatScreen,},
Dashbaord: {screen: DashbaordScreen,},
Profile: {screen: ProfileScreen,},
Search: {screen: SearchScreen,},
},
{
initialRouteName: "Contacts",
tabBarPosition: "bottom",
tabBarOptions: {
showIcon: true,
activeTintColor: 'white',
}
}
);
export default () => <LoggedInNavigator onNavigationStateChange={null} />
export const Drawer = DrawerNavigator ({
Home:{
screen: Screen1,
navigationOptions: {
drawer:{
label: 'Home',
},
}
},
Camera: {
screen: Screen2,
navigationOptions: {
drawer:{
label: 'Camera',
},
}
},
})
Contants.js
class Contacts extends Component {
componentDidMount() {
// TBD loggedin should come from login process and removed from here
const { loggedIn, getContacts } = this.props;
loggedIn(1);
getContacts();
}
render() {
const Router = createRouter( () => ({})); //IDAN
const { navigation, avatar, contacts } = this.props;
return (
<NavigationProvider router={Router}>
<View style={{flex:1}}>
<ContactView
navigation={navigation}
avatar={avatar}
contacts={contacts}
/>
<Drawer />
</View>
</NavigationProvider>
);
}
}
const mapStateToProps = (state) => {
return (
{
avatar: state.user.user.avatar,
contacts: state.contacts.contacts,
}
);
};
export default connect(mapStateToProps, { loggedIn, getContacts })(Contacts);
Help me please..
After a while, i want to answer on my own question (with react-navigation v2)
everything inside <RootNavigator/>
const RootNavigator= createDrawerNavigator({ Tabs }, {
contentComponent: SideMenu,
drawerWidth: Dimensions.get('window').width * .75,
})
SideMenu:
class SideMenu extends Component {
render() {
return ( //...your side menu view )
}
}
Tab:
export default createBottomTabNavigator({
Menu: {
screen: HomeStack,
navigationOptions: {
title: 'תפריט',
tabBarIcon: ({ focused, tintColor }) => {
return <Icon name={'home'} size={20} color={tintColor} />;
},
}
},
Dashboard: {
screen: DashboardStack,
navigationOptions: {
title: 'בית',
tabBarOnPress: ({ navigation, defaultHandler }) => handleTabPress(navigation, defaultHandler),
tabBarIcon: ({ focused, tintColor }) => {
return <Icon name={'dashboard'} size={20} color={'green'} />;
},
}
},
QuickView: {
screen: QuickNav,
navigationOptions: {
title: 'מבט מהיר',
tabBarIcon: ({ focused, tintColor }) => {
return <Icon name={'short-list'} size={20} color={tintColor} />;
},
},
},
Chat: {
screen: Chat,
navigationOptions: {
title: "צ'אט",
tabBarIcon: ({ focused, tintColor }) => {
return <Icon name={'chat'} size={20} color={tintColor} />;
},
},
},
},
{
initialRouteName: 'Dashboard',
tabBarOptions: {
activeTintColor: 'green',
labelStyle: {
fontSize: 16,
marginBottom: 3,
},
},
},
)
For v5 onwards you can use drawer style
import deviceInfoModule from 'react-native-device-info';
<Drawer.Navigator
drawerStyle={{
width: deviceInfoModule.isTablet()
? Dimensions.get('window').width * 0.55
: Dimensions.get('window').width * 0.7,
}}
You can set the drawer width using Dimensions width. See the docs here
https://reactnavigation.org/docs/navigators/drawer
import { Dimensions } from 'react-native';
...
const { width } = Dimensions.get('screen');
...
export const Drawer = DrawerNavigator (
{
Home:{
screen: Screen1,
navigationOptions: {
drawer:{
label: 'Home',
},
}
},
Camera: {
screen: Screen2,
navigationOptions: {
drawer:{
label: 'Camera',
},
}
},
},
{
drawerWidth: width
});
In react-navigation version 6, you can use the drawerStyle in the screenOptions prop in the Drawer.Navigator component to change the width and add styles. This applies the applied style to all screens in the navigator.
<Drawer.Navigator
screenOptions: {{
drawerStyle: {
width: 240
}
}}
>
If you want the drawer to cover the entire screen, then import Dimensions from the react-native library and use Dimensions.get('window').width
import { Dimensions } from 'react-native'
<Drawer.Navigator
screenOptions: {{
drawerStyle: {
width: Dimensions.get('window').width
}
}}
>
Refer to react-navigation drawer for more.