Unable to navigate using reusable card components in React Native - react-native

I have this HomeScreen file, in it I have added Card component(Dashboard & Highlights), I have Customized the Card Components with the TitleCard to reuse the styling,
In each card there is "View All" Button to navigate to its individual Screens,
When I don't use the Cards and put the entire code in home screen and Click on the View All Button on home screen then it navigates to that page, but when I use the Cards and use its props to navigate to the link provided as forwardLink props then
I get this error
"ReferenceError: Can't find variable: navigation"
Also when I add this.props.navigation.navigate('{props.forwardLink}') in TitleCard
I get this error message:
TypeError: undefined is not an object (evaluating '_this.props.navigation')
Here are the codes for each file
TitleCards
import React from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const TitleCards = props => {
return (<View style={styles.textTitlesContainer}>
<Text style={styles.textTitle}>{props.leftTitle}</Text>
<TouchableOpacity
onPress={() => navigation.navigate('{props.forwardLink}')}>
<Text style={[styles.textTitle, {color: '#F483A7'}]}>
{props.rightTitle}
</Text>
</TouchableOpacity>
</View>)
};
const styles = StyleSheet.create({
textTitlesContainer: {
flex: 1,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
padding: 5,
},
textTitle: {
fontSize: 20,
fontWeight: '800',
color: '#fff',
},
});
export default TitleCards;
HomeScreen
import React, {Component} from 'react';
import {
SafeAreaView,
ScrollView,
StyleSheet,
} from 'react-native';
import {CustomHeader} from '../index';
import Colors from '../constants/Colors';
import DashboardCard from './DashboardCard';
import HighlightCard from './HighlightCard';
export class HomeScreen extends Component {
render() {
return (
<SafeAreaView style={{flex: 0, backgroundColor: Colors.primary}}>
<CustomHeader
title="Home"
isHome={true}
navigation={this.props.navigation}
/>
<ScrollView style={styles.container}>
<DashboardCard />
<HighlightCard />
</ScrollView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
height:900, backgroundColor: Colors.mainBackground,
paddingTop:6,
},
});
export default HomeScreen;
HighlightCard
import React, {Component} from 'react';
import {Text, View} from 'react-native';
import {CustomHeader} from '../../index';
const HighlightCard = (prop) => {
return (
<Card>
<TitleCards leftTitle="Highlights" rightTitle="View More" forwardLink="Highlights">
</TitleCards>
<View>
<Text>News Feed</Text>
</View>
</Card>
);
};
export default HighlightCard;
const styles = StyleSheet.create({
textTitle: {
fontSize: 20,
fontWeight: '800',
color: '#fff',
},
});
When I use the HighlightCard codes directly in HomeScreen then it navigates to that page, below is that code which works if I use it directly in Home Screen
*{/* <Text style={styles.textTitle}>Highlights</Text>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Highlights')}>
<Text style={[styles.textTitle, {color: '#F483A7'}]}>View All</Text>
</TouchableOpacity> */}*
I think there is something wrong I am doing is using the props or referencing to the navigation page
I also tried creating a const for navigation
const {navigate} = this.props.navigation
this didn't worked either

Related

Problem with lining up contents: react native

I'm currently having a problem with the clickable size of a reusable button which includes an icon and text. When I run this code it seems like the entire row becomes clickable when I only want the icon and text to become clickable. Does anyone know how to solve this problem? Thanks
App.js
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import IconTextButton from './components/iconTextButton';
export default function App() {
return (
<View style={styles.container}>
<Text style={{marginTop: 100}}>My First React App! Sike </Text>
<IconTextButton iconFont="ionicons" iconName="pencil" iconSize={25} text="Add Items"/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'powderblue',
},
});
iconTextButton.js
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon}>
<Text style={styles(iconSize).buttonText}>{text}</Text>
</FontIcon>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})
Along with the code I've tried, I've also tried to keep and as seperate contents whilst adding a flexDirection: 'row' inside styles.container. This keeps the contents in the same line but it still makes the whole row clickable. I've also tried putting everything in a and moving the styles.container to the component and adding a height: size into styles.container. This makes the clickable component limited however, the component is hidden underneath due to the restricted height. I have also tried simply just using instead of making a reusable const that its an input. The same thing applies.
You can wrap your Icon and Text Component in a View component and then wrap it inside a TouchableOpacity Component
Try this or do something like this :
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container}>
<View style={styles(iconSize).iconTextContainer}>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon} />
<Text style={styles(iconSize).buttonText}>{text}</Text>
</View>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
iconTextContainer: {
flexDirection: 'row',
alignItems: 'center',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})

Cannot read property 'navigation' of undefined Evaluating App.js Loading App.js

Looking to have button enter go into another screen:
need help with navigation screen.
I keep getting error:
Cannot read property 'navigation' of undefined
Evaluating App.js
Loading App.js
TypeError: Cannot read property 'navigation' of undefined
https://snack.expo.io/#ganiyat1/colorful-thrills
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground, Image, Button } from 'react-native';
import Constants from 'expo-constants';
import { StackNavigator} from 'react-navigation';
import Books from './components/Books';
// You can import from local files
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
const Book = StackNavigator({
Books: { screen: Books },
});
const { navigate } = this.props.navigation;
export default function App() {
return (
<View style={styles.container}>
<View style={styles.topContainer}>
<Text style={styles.title}> Colorful Thrills
</Text >
</View>
<View style={styles.bottomContainer}></View>
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require('./assets/bookcover.png')}
/>
<Text style={styles.paragraph}>
{"\n"} BOOKWORMS, UNITE! {"\n"} {"\n"}
Suspense, Mystery and Thrillers by Authors of Color
</Text>
<Button
color='#ff914d'
title= 'ENTER'
onPress={() =>
navigate('Books')}
/>
</View>
</View>
);
}
In the above code snippet, I don't see a default Navigator being returned form the entry file, which is App.js by default in React Native.
I assume that you just started to learn React Native, so I will spare you all the minor details and walk you through the solution.
I refactored the App.js file to a into a new component file in /components/Home.js.
Added a default stack Navigator in App.js which has two screens, Home and Books.
Now you can access all the Navigation props in your Home and Books component, as it is being declared in the Navigator variable in App.js
Here is a live demo of your code on Expo.
//App.js
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground, Image, Button } from 'react-native';
import Constants from 'expo-constants';
import { StackNavigator} from 'react-navigation';
import Books from './components/Books';
import Home from './components/Home'
import { Card } from 'react-native-paper';
const Navigator = StackNavigator({
Books: { screen: Books },
Home:{screen:Home}
});
export default function App(props) {
return (
<Navigator />
);
}
//component/Books.js
import React, { useState } from 'react';
import { StyleSheet, SafeAreaView,Button } from 'react-native';
import MaterialTabs from 'react-native-material-tabs';
const Books = (props) => {
const {navigation} = props
const [selectedTab, setSelectedTab] = useState(0);
return (
<SafeAreaView style={styles.container}>
<MaterialTabs
items={['New Releases', 'All', 'BOM']}
selectedIndex={selectedTab}
onChange={setSelectedTab}
barColor="#1fbcd2"
indicatorColor="#ff914d"
activeTextColor="white"
/>
<Button
color='#ff914d'
title= 'Home'
onPress={() =>
navigation.navigate('Home')}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default Books
//component/Home.js
import React from 'react'
import {View,Text,StyleSheet,Button,Image} from 'react-native'
const Home = (props) => {
const {navigation} = props
return (
<View style={styles.container}>
<View style={styles.topContainer}>
<Text style={styles.title}> Colorful Thrills
</Text >
</View>
<View style={styles.bottomContainer}></View>
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require('../assets/bookcover.png')}
/>
<Text style={styles.paragraph}>
{"\n"} BOOKWORMS, UNITE! {"\n"} {"\n"}
Suspense, Mystery and Thrillers by Authors of Color
</Text>
<Button
color='#ff914d'
title= 'ENTER'
onPress={() =>
navigation.navigate('Books')}
/>
</View>
</View>
)
}
export default Home
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
topContainer: {
flex: 1,
backgroundColor: '#ff914d',
},
bottomContainer: {
flex: 1,
backgroundColor: '#96d0e3',
},
imageContainer: {
position: 'absolute',
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
image: {
width: 300,
},
title:{
margin: 24,
marginTop: 50,
fontSize: 40,
fontWeight: 'bold',
textAlign: 'center',
fontFamily: 'GillSans-Italic',
},
paragraph: {
margin: 24,
marginTop: 0,
fontSize: 20,
fontWeight: 'bold',
textAlign: 'center',
}
});

TypeError: undefined is not an object (evaluating props.navigation.navigate)

I have an icon on the right side of my Header. When pressed I want to be transferred to another page. However, it comes up with an error.
This is my 'icon' screen:
import React, { Component } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
const Login = props => {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => {
props.navigation.navigate({routeName: 'Login'});}}>
<Image
source={{
uri:
'https://clipartart.com/images/login-icon-clipart-5.jpg',
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
}
export default Login;
This is my 'navigation' screen:
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import React from 'react';
import Homepage from './screens/Homepage';
import Checkoutpage from './screens/Checkoutpage';
import Filterpage from './screens/Filterpage';
import Locationpage from './screens/Locationpage';
import Menupage from './screens/MenuPage';
import Welcomepage from './screens/Welcomepage';
import Loginpage from './screens/Loginpage';
import Finalpage from './screens/Finalpage';
import Login from './Components/Login';
const Navigation = createStackNavigator({
Home:Homepage,
Checkout: Checkoutpage,
Filter: Filterpage,
Location: Locationpage,
Menu: Menupage,
Welcome: Welcomepage,
Login: Loginpage,
Final: Finalpage
},
{
defaultNavigationOptions: {
headerRight:() => <Login/>
}
}
);
I'm very new to react-native. So if you found the problem, can you please explain thoroughly so I understand. Thank you!!
So it looks like you are expecting the navigation object to be part of the props passed to your <Login/> component. This object is only defined for screen components in react-navigate.
This means that you need to get access to the navigation functionality some other way. Luckily, this library provides you with the useNavigation() hook. So using that in your component would look something like:
// react-navigation v5+
import { useNavigation } from '#react-navigation/native';
const Login = () => {
const navigation = useNavigation();
return (
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
onPress={() => {
navigation.navigate({ routeName: "Login" });
}}
>
<Image
source={{
uri: "https://clipartart.com/images/login-icon-clipart-5.jpg",
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
};
It seems to me you are using React Navigation v4.x , in order to use the useNavigation hook you need to upgrade to v5.x.
The navigation prop will be passed to all screens by default and you can use the useNavigation hook like #faelks suggested (if needed in other components).
UPGRADE TO v5 FIRST.
Here you have a little example for v5.x version:
import React from 'react'
import { Button, View, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
const Home = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go to login" onPress={() => navigation.navigate('Login')} />
</View>
)
const Login = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
const Main = createStackNavigator()
const mainConfig = {
// configuration for this stack
initialRouteName: "Home",
}
export default props => (
<NavigationContainer>
<Main.Navigator {...mainConfig}>
<Main.Screen name="Home" component={Home} />
<Main.Screen name="Login" component={Login} />
{/* Other screens for this stack */}
</Main.Navigator>
</NavigationContainer>
)
const styles = StyleSheet.create({
component: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})

How do i navigate between screens in my shopping app?

'm new to react-native and mobile application. I'm trying to build a basic shopping app.i have the sports options such as cricket,football,tennis and whenever the cricket button is pressed, the cricket products must be displayed and i can follow it up for the other two products
i tried using stack navigator to navigate between screens but i seem to get a error . i tried using createstacknavigator but it doesnt come out right
1.App.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
import FirstScreen from './src/FirstScreen'
import SecondScreen from './src/cricket'
const Navigation = StackNavigator({
First: {screen: FirstScreen},
Second: {screen: SecondScreen}
});
export default Navigation
AppRegistry.registerComponent('AwesomeProject', () => Navigation);
2.FirstScreen.js
import React, { Component } from 'react';
import { Alert, AppRegistry, Image, Platform, StyleSheet, Text,
TouchableHighlight, TouchableOpacity, TouchableNativeFeedback,
TouchableWithoutFeedback, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
export default class FirstScreen extends Component {
//_onPressButton() {
// Alert.alert('You tapped the button!')
//}
//_onLongPressButton() {
//Alert.alert('You long-pressed the button!')
//}
static navigationOptions = {
title: 'First Screen',
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Cricket</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Football</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Tennis</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 60,
alignItems: 'center'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
padding: 20,
color: 'white'
}
});
// skip this line if using Create React Native App
//AppRegistry.registerComponent('AwesomeProject', () => Touchables);
3.Cricket.js
import React, { Component } from 'react';
import {Alert, Button, ScrollView, StyleSheet, AppRegistry, Text, View
} from 'react-native';
const styles = StyleSheet.create({
rowContainer: {
flex: 1,
height: 75,
width: '100%',
flexDirection: 'row', // children will be on the same line
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonContainer: {
flex: 1,
},
text: {
flex: 2, // Text takes twice more space as button container
color: 'red',
fontWeight: 'bold',
fontSize: 20,
},
});
class Greeting extends Component {
static navigationOptions = {
title: 'Second Screen',
};
_onPressButton() {
Alert.alert('Sorry you have no credit!')
}
render() {
return (
<View style={styles.rowContainer}>
<Text style={styles.text}>{this.props.name}</Text>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="BUY"
/>
</View>
</View>
);
}
}
export default class SecondScreen extends Component {
render() {
return (
<ScrollView>
<View style={{alignItems: 'flex-start', top: 0, flex: 2,
backgroundColor: 'black'}}>
<Greeting name='Shoe- 800' />
<Greeting name='Jersey - 350' />
<Greeting name='Stockings - 100' />
<Greeting name='Cones - 50' />
<Greeting name='Whistle - 80' />
<Greeting name='Helmet - 750' />
<Greeting name='Tennis Ball-6 pack - 800' />
<Greeting name='Nets - 1500' />
<Greeting name='Leg Pads - 1000' />
<Greeting name='Stumps - 800' />
<Greeting name='Gloves - 600' />
</View>
</ScrollView>
);
}
}
When the cricket button is pressed, the screen should navigate to the list of cricketproducts which is the (cricket.js)
As you are using react-navigation, you just need to use the navigation prop. You have commented the part where you handle the press. Just change that function to actually navigate to the screen you want:
_onPressButton=()=>{
this.props.navigation.navigate("Second")
}
If you are not using arrow functions, you need to bind the function to have access to the this of that screen. To do that you need to add inside your constructor:
constructor(props){
super(props)
this._onPressButton.bind(this)
}
after that you can call it by doing:
_onPressButton() {
this.props.navigation.navigate("Second")
}
As you are using a stackNavigator, you have different ways to navigate to the other screen of the same stack. You have different ways to navigate. For example:
this.props.navigation.push("Second")
This method pushes a new screen to the stack, no matter what screen it is
this.props.navigation.navigate("Second")
Navigates to a new screen in the stack, will push it in the stack only if the screen hasn't been focussed before
this.props.navigation.replace("Second")
This will navigate to a new screen without pushing it to the stack, "replacing" the screen you was watching with the new one.
EDIT.
For the error you stated in the comment, it's because there's not an app container. To do so, just do:
import { createStackNavigator, createAppContainer } from 'react-navigation'
Then do
const Navigation = createAppContainer(createStackNavigator({
First: {screen: FirstScreen},
Second: {screen: SecondScreen}
}));
Use the Move Screen command.
this.props.navigation.navigate("Second")

this.props.navigation undefined is not an object

I am new in react native. I am using React navigation. But navigation is not working, giving an error:-
"props.navigation undefined is
not an object"
I am giving my project structure and code.
Project Structure:-
Code in App.js:-
import { createStackNavigator, createDrawerNavigator } from 'react-navigation';
import HomeLayout from './src/components/Home/Layout';
import SideMenuLayout from './src/components/DrawerMenu/SideMenu';
import { DetailsScreen } from './DetailsScreen';
const myDrawer = createDrawerNavigator({
Home:{
screen: HomeLayout
},
Details:{
screen: DetailsScreen
},
},{
contentComponent: SideMenuLayout,
drawerWidth: 876/3
})
const native = createStackNavigator({
Home:{
screen: myDrawer,
},
},{
headerMode: 'none',
})
export default native;
SideMenu.js(Layout for drawer navigator). In this section All menus has been rendered.-
import React, {Component} from 'react';
import { View, StyleSheet} from 'react-native';
import DrawerHeader from './DrawerHeader';
import DrawerMenu from './DrawerMenu';
class SideMenuLayout extends Component {
state = {
menuNames:[{
id:'0',
name:'My Profile'
},{
id:'1',
name:'Place Order'
},{
id:'2',
name:'Order History'
},{
id:'3',
name:'Payment'
},{
id:'4',
name:'Recharge'
},{
id:'5',
name:'Help'
},{
id:'6',
name:'Logout'
}]
}
render () {
return (
<View style={styles.container} >
<DrawerHeader/>
<DrawerMenu menuItems={this.state} style={{ marginTop: 106/3}}/>
</View>
);
}
}
export default SideMenuLayout;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor: "#ffffff",
}
});
Drawer Menu.js. In this section all menus are rendered and want to navigate from here.
import React, {Component} from 'react';
import {FlatList, Text, View, StyleSheet,TouchableOpacity} from 'react-native';
import Dash from 'react-native-dash';
import { FontAwesome } from '#expo/vector-icons';
import { StackNavigator } from 'react-navigation';
const DrawerMenu = (props)=>{
const { navigate } = props.navigation;
return (
<View style={styles.menuContainer}>
<FlatList
data={props.menuItems.menuNames}
renderItem={(info) => (
<View>
<View
style={{
width:690/3,
backgroundColor: '#ffffff',
height:141/3,
paddingTop:48/3,
flexDirection:'row',
marginBottom:7
}}>
<View style={{position:"relative",width:390/3,height:'100%',backgroundColor:'#ffffff',alignSelf: 'flex-start'}}>
<TouchableOpacity onPress={()=>navigate('Details')}>
<Text style={{color:'#615b5b',fontSize:18,fontFamily:'sans-serif'}}>
{info.item.name}
</Text>
</TouchableOpacity>
</View>
<View
style={{
alignItems:"center",
justifyContent:'center',
position:"relative",
width:300/3,
backgroundColor:'#ffffff',
paddingRight:10,
paddingBottom:5,
}}>
<FontAwesome
style={{ alignSelf: 'flex-end'}}
name="angle-right"
size={18}
color="#615b5b"
/>
</View>
</View>
<Dash dashColor = '#d6d6d6' style={{width:'100%', height:1,alignSelf: 'flex-start'}}/>
</View>
)}
keyExtractor={(info, index) => info.id}
/>
</View>
);
}
export default DrawerMenu;
const styles = StyleSheet.create({
menuContainer:{
width: 700/3,
height:1425/3,
alignSelf: 'flex-end',
backgroundColor: '#ffffff',
paddingTop: 61/3,
}
});
The SideMenuLayout has a navigation prop passed to it automatically by the Drawer. So you need to pass that further to your DrawerMenu
<DrawerMenu navigation={this.props.navigation} menuItems={this.state} style={{ marginTop: 106/3}}/>
...
export default SideMenuLayout;
SideMenuLayout.propTypes = {
navigation: PropTypes.object // Or use flow, or it does not really matter. It's just type validation.
}
And the you can use navigate in your DrawerMenu like you use it now.