I have an ApplicationHeader Component and I want to navigate to a specific screen on touch, but I'm getting
undefined is not an object (evaluating this.props.navigation.navigate)
App.js
render() {
return (
<SafeAreaView forceInset={{ bottom: 'never' }} style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<Provider store={store}>
<ApplicationHeader navigation={this.props.navigation} />
<AppNavigator />
</Provider>
</SafeAreaView>
);
}
ApplicationHeader.js
class ApplicationHeader extends Component {
constructor(props) {
super(props)
}
openWishlist() {
this.props.navigation.navigate('Wishlist')
}
render() {
const { isLogged } = this.props;
return (
<View style={AppStyle.header}>
<TouchableOpacity onPress={() => this.openWishlist()}>
{!isLogged && (<Image source={imgWishList} style={AppStyle.headerWishlist} />)}
{isLogged && (<Image source={imgWishListLogged} style={AppStyle.headerWishlist} />)}
</TouchableOpacity>
</View>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ApplicationHeader);
It seems like that your HeaderComponent is might not be in Navigation Stack.
In that case, you can try the following solution:
First import withNavigation in your file like
import { withNavigation } from 'react-navigation';
After that change your component export to
export default connect(
mapStateToProps,
mapDispatchToProps
)(withNavigation(ApplicationHeader));
So you will get the access to navigation pros in this component.
Also your ApplicationHeader can move to inner container components. It shouldn't have to be in App.js to use the navigation props.
Hope this will help you.
Related
I am using class components with react navigation5 and I have two classes :
Class DrawerComponent.js
export default class DrawerContent extends Component{
constructor(props){
super(props);
}
render(){
return(
<View style={{flex:1}}>
<DrawerContentScrollView {...this.props}>
<Drawer.Section style={styles.drawerSection}>
{
<DrawerItem
icon={({color,size}) => (
<Icon
name=""
color={color}
size={size}
/>
)}
label={menu.localizedTitle}
onPress = {() =>**{this.props.navigation.navigate("RecordList",{body :'abc' }**)}}/>)
</Drawer.Section>
</View>
</DrawerContentScrollView>
</View>
)}}
Now if I have to access value of body in another class, how can I do so?
in your RecordList component, you can access the params with route
const RecordList = ({navigation, route})=>{
const {body} = route.params;
console.log(body)
}
in class based component:
class RecordList extends Component{
render(){
const {body} = this.props.route.params;
console.log(body)
return <View><Text>{body}</Text></View>
}
}
I am using stackNavigator inside drawerNavigator so I will have to use nested navigation:
this.props.navigation.navigate('RecordList', {screen:'Home',params :{ title: "Home"}})
and retrieving can be done exactly like how it is done above in Ketan's answer.
I am doing stack navigation but I can't seem to be able to navigate I will get this error "Can't find variable: navigate" Here is the screenshot of my android emulator
This is my App class(main)
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Header/>
<AppNavigator/>
</View>
);
}
}
const AppNavigator = StackNavigator({
Cluster1: {
screen: Cluster1,
},
Play: {
screen: Play,
},
});
This is my Cluster1 class
export default class Cluster1 extends Component{
render(){
return(
<View>
<SectionList
renderSectionHeader={({ section }) => {
return (<SectionHeader section={section} />);
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
>
</SectionList>
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={() => { navigate("Play");}}>
<Text style ={styles.Play}>Play
</Text>
</TouchableOpacity>
</View>
);
}
}
navigation object only exist in the screen component. (not exist in the nested components). you can pass it into the nested component using props
export default class Cluster1 extends Component{
render(){
return(
<View>
<SectionList
renderSectionHeader={({ section }) => {
return (<SectionHeader navigation={this.props.navigation} section={section} />);
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
>
</SectionList>
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={() => { this.props.navigation.navigate("Play");}}>
<Text style ={styles.Play}>Play
</Text>
</TouchableOpacity>
</View>
);
}
}
Include on your SectionHeader the this.props.navigation something like this:
<SectionHeader navigation={this.props.navigation}/>
because the props.navigation are by default on your parent component
and on SectionHeader component you will access to navition like:
..
goToSignUp() {
this.props.navigation.navigate('SignUp');
}
..
For me also was confusing before. Cheers!
You can use this rather than navigate :
this.props.navigation.navigate('Play')
Hope this is helpful.
I have created a composed component to compose TouchableNativeFeedback to wrapperComponent.
export default function withFeedback2(
WrappedComponent
) {
return class extends BaseComponent {
constructor(props) {
super(props);
}
render() {
return (
<View>
<TouchableNativeFeedback
onPress={() => this.props.onContainerViewPress()}
>
<WrappedComponent {...this.props} />
</TouchableNativeFeedback>
{/* <TouchableOpacity
onPress={this.props.onContainerViewPress ? () => this.props.onContainerViewPress() : null}
>
<WrappedComponent {...this.props} />
</TouchableOpacity> */}
</View>
);
}
};
}
But OnPress event of TochableNativeFeedback is not firing. Whereas OnPress event is fired correctly and onContainerViewPress prop of wrappercomponent is called if wrappercomponent wrapped under TouchableOpacity.
I am testing this on the Android Platform.
Use a <View></View> to wrap your WrappedComponent for TouchableNativeFeedback.
<TouchableNativeFeedback
onPress={() => this.props.onContainerViewPress()}>
<View>
<WrappedComponent {...this.props} />
</View>
</TouchableNativeFeedback>
There are two different TouchableNativeFeedback classes. Make sure you import the correct one:
import { TouchableNativeFeedback } from "react-native"
import { TouchableNativeFeedback } from "react-native-gesture-handler"
I had a similar problem and finally used it from "react-native" library. Importing it from "react-native-gesture-handler" did not work for me.
I've discovered that adding a Ripple effect to the TouchableNativeFeedback fixes the issue for me:
background={TouchableNativeFeedback.Ripple("#FFFFFF",true)}
i.e.
export default function withFeedback2(
WrappedComponent
) {
return class extends BaseComponent {
constructor(props) {
super(props);
}
render() {
return (
<View>
<TouchableNativeFeedback
onPress={() => this.props.onContainerViewPress()}
background={TouchableNativeFeedback.Ripple("#FFFFFF",true)}
>
<WrappedComponent {...this.props} />
</TouchableNativeFeedback>
</View>
);
}
};
}
Try: useForeground={true}
<TouchableNativeFeedback onPress={() => {}} useForeground={true}>
You can call method as below:
export default function withFeedback2(
WrappedComponent
) {
return class extends BaseComponent {
constructor(props) {
super(props);
this.onContainerViewPress = this.onContainerViewPress.bind(this);
}
onContainerViewPress() {
const { onContainerViewPress } = this.props;
onContainerViewPress();
}
render() {
return (
<View>
<TouchableNativeFeedback
onPress={() => { this.onContainerViewPress(); }}
>
<WrappedComponent {...this.props} />
</TouchableNativeFeedback>
{/* <TouchableOpacity
onPress={this.props.onContainerViewPress ? () => this.props.onContainerViewPress() : null}
>
<WrappedComponent {...this.props} />
</TouchableOpacity> */}
</View>
);
}
};
}
Try to import Touchable native feedback from react native gesture handler library
import { TouchableNativeFeedback } from "react-native"
import { TouchableNativeFeedback } from "react-native-gesture-handler"
Supplementing the answer of mangei the problem could be if you import it from the wrong place. You have to import it from react-native-gesture-handler if you are inside a gesture handler (NOTE: react-navigation's TabBar itself has a PanGestureHandler in it by default). What react-native-gesture-handler does is it wraps components like ScrollView or TouchableNativeFeedback with its own implementation to be able to handle gestures inside the GestureHandler as well that are "not meant" for the GestureHandler but rather for the ScrollView or the TouchableNativeFeedback. If you're inside the gesture handler, you have to import it from react-native-gesture-handler else from react-native.
I am building a POC application in react-native and trying to implement react-navigation
import {StackNavigator, DrawerNavigator} from 'react-navigation';
export default class HomeScreen extends React.Component {
constructor(props) {
super(props)
this.clicked = this.clicked.bind(this)
}
static navigationOptions = {
drawerLabel: 'Home',
};
clicked = ()=> {
this.props.navigator.navigate('DrawerOpen'); // open drawer
}
render() {
// const {navigate} = this.props.navigation;
return (
<ScrollView>
<View style={styles.container}>
<View style={styles.header}>
<View style={{width: 50}}>
<TouchableHighlight onPress={()=> {
this.clicked("DrawerOpen")
}}>
<Image source={require('./img/hamburger_icon.png')}/>
</TouchableHighlight>
</View>
</View>
</View>
</ScrollView >
)
}
}
Now whenever I am clicking on touchable highlight, clicked function gets called and it shows error:
undefined is not an object (evaluating '_this.props.navigator.navigate')
clicked
You try it :)
import {StackNavigator, DrawerNavigator} from 'react-navigation';
export default class HomeScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Home',
};
clicked = () => {
this.props.navigation.navigate('DrawerOpen'); // open drawer
}
render() {
// const {navigate} = this.props.navigation;
return (
<ScrollView>
<View style={styles.container}>
<View style={styles.header}>
<View style={{width: 50}}>
<TouchableHighlight onPress={()=>
this.clicked()
}>
<Image source={require('./img/hamburger_icon.png')}/>
</TouchableHighlight>
</View>
</View>
</View>
</ScrollView >
)
}
}
Try this , May be this can help you, Inside the clicked
clicked = ()=> {
this.props.navigation.navigate('DrawerOpen');
}
This just happened to me. Only the top level components get the this.props.navigation.
Probably you have to call this component like this:
<HomeScreen navigation=this.props.navigation />
I want to set up a sidebar menu with Drawer (Native Base).
I have a App.js :
export default class ReactProject extends Component {
renderScene (route, navigator) {
return <route.component navigator={navigator} />
}
render() {
return (
<Navigator
style={styles.container}
renderScene={this.renderScene.bind(this)}
initialRoute={{component: Home}}
/>
);
}
}
A Home.js with the drawer :
export default class Home extends Component {
render() {
return (
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar />} navigator={this.props.navigator}>
<Container>
</Container>
</Drawer>
);
}
}
And sidebar.js which is loaded into the drawer :
export default class SideBar extends Component {
constructor(props) {
super(props);
}
redirect(routeName){
this.props.navigator.push({
component: routeName
});
}
render() {
return (
<Content style={styles.sidebar}>
<ListItem button >
<Text>Home</Text>
</ListItem>
<ListItem button >
<Text>Test</Text>
</ListItem>
<ListItem button onPress={this.redirect.bind('Blank')}>
<Text>Blank Page</Text>
</ListItem>
</Content>
);
}
}
But when I click i have this error:
Undefined is not an object (evaluating 'this.props.navigator.push')
I do not have this problem when the button is in the page but only in the sidebar.js
Could someone help me?
thank you,
Thomas.
I think you have to change little bit code of your Home.js as per mentioned below:
render() {
return (
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar navigator={this.props.navigator} />}
<Container>
</Container>
</Drawer>
);
And add this lines of code in your sidebar.js file:
static propTypes = {
navigator: React.PropTypes.object,
}