I'm trying to work with React Navigation using an external button component, to make styling it easier, but it gives me the TypeError: undefined is not an object (evaluating '_this.props.navigation') error when I try to pass the navigation. If I create the button on my home screen it works fine, but that clutters up my HomeScreen's stylesheet, and means I have to repeat code when I use the button elsewhere.
I have the stack navigation set up in my App.js, and again, it works fine when I'm not trying to pass the navigation as a prop.
Here's HomeScreen.js
import React from "react";
import {
ScrollView,
StyleSheet,
Text,
View,
AsyncStorage,
} from 'react-native';
import Heading from '../heading';
import Input from '../Input';
import Button from "../Button";
export const Home = ({navigation}) => (
<View style={styles.container}>
<ScrollView style={styles.content}>
<Heading />
</ScrollView>
<Button/>
</View>
)
And here's my Button.js
/* eslint-disable prettier/prettier */
import React from 'react';
import {
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native';
import { useNavigation } from '@react-navigation/native';
function Button(){
const navigation = useNavigation()
return(
<View style={styles.buttonContainer}>
<TouchableHighlight
underlayColor='rgba(175, 47, 47, .75)'
activeOpacity={1.0}
style={styles.button}
onPress={() => {
navigation.navigate("New Medication");
}}>
<Text style={styles.submit}>
+
</Text>
</TouchableHighlight>
</View>
)
}
As far as I understand it, this should work just fine, so why is it saying that it's being passed as undefined?
UPDATE: Thanks to some suggestions I now have it to where it doesn't give an error, just does nothing.
Here's my App.js, with my navigation
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="NewMedication" component={newMedScreen} />
</Stack.Navigator>
);
}
class App extends Component{
render(){
return(
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
}
export default App;
I recommend you to create a const with screen name and reuse it everywhere to avoid such problem. You nave stack like this <Stack.Screen name="NewMedication" component={newMedScreen} /> , but try to navigate
navigation.navigate("New Medication").Of course this screen do not exist
const NEW_MEDICATION_SCREEN = 'NewMedication'
<Stack.Screen name={NEW_MEDICATION_SCREEN} component={newMedScreen} />
.....
onPress={() => navigation.navigate(NEW_MEDICATION_SCREEN)}>
and for make Button reusable use it like this
function Button({onPress}){
return(
<View style={styles.buttonContainer}>
<TouchableHighlight
underlayColor='rgba(175, 47, 47, .75)'
activeOpacity={1.0}
style={styles.button}
onPress={onPress}>
<Text style={styles.submit}>
+
</Text>
</TouchableHighlight>
</View>
)}
export const Home = ({navigation}) => (
<View style={styles.container}>
<ScrollView style={styles.content}>
<Heading />
</ScrollView>
<Button onPress={() => navigation.navigate(NEW_MEDICATION_SCREEN)}/>
</View>