I have a cart icon as a header-right button for almost all screens. I am using react-navigation5.
I want to update the badge count on that button from my components.
Any possible way to achieve it without using redux or flux library?
following is my code for example:
route.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Home, Cart, Wishlist, Login, Signup, Contact, Profile, Search } from './scenes';
import { Primary, Secondary } from './assets/color';
import { HeaderButton } from './components'
const Stack = createStackNavigator();
function Route() {
return (
<Stack.Navigator initialRouteName="Profile" screenOptions={({ navigation, route }) =>({ headerRight:()=>(<HeaderButton navigation={navigation} nav='Cart'/>)})}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Cart" component={Cart} options={{headerRight:null}}/>
<Stack.Screen name="Search" component={Search} />
</Stack.Navigator>
);
}
export default Route;
headerButton.js
import React, { Component } from "react";
import { View } from 'react-native'
import { Button, Icon, Badge, Text } from 'native-base';
import { Primary, Danger } from '../../assets/color'
export class HeaderButton extends Component{
render(){
return(
<>
<Button rounded transparent onPress={()=>this.props.navigation.push('Cart')}>
<Icon type='MaterialIcons' name='shopping-cart' style={{color:Primary,right:6,top:2}}/>
</Button>
<Text>{this.props.count}</Text>
</>
);
}
}
home.js
import React, { Component } from "react";
import { View } from 'react-native'
import { Button, Icon, Badge, Text } from 'native-base';
import { Primary, Danger } from '../../assets/color'
export class Home extends Component{
constructor(){
super();
this.state={
count:1
}
}
addToCart=()=>{
var varcount=this.state.count;
varcount=varcount+1;
this.setState({count:varcount})
}
render(){
return(
<Button onPress={this.addToCart}>
<Text>Add to cart</Text>
</Button>
);
}
}
Whenever count is changed in the app it must be reflected in headerbutton component which is in route.js as headerRight
When ever you call the addToCart, you should add parenthesis to it since it has a function value, it should be addToCart().
Also whenevery you call addToCart() The value will not change because the scope the varcount is only local, I suggest you make it global so it will not reset the value
I have solved it by myself, using passing parameters from parent to child and vise versa.
The following are the changes I have made in my code.
route.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Home, Cart, Wishlist, Login, Signup, Contact, Profile, Search } from './scenes';
import { Primary, Secondary } from './assets/color';
import { HeaderButton } from './components'
const Stack = createStackNavigator();
function Route() {
const [count, setCount] = React.useState(0);
const onCount=(value)=>{
setCount(value);
console.log(count, value);
}
return (
<Stack.Navigator initialRouteName="Profile" screenOptions={({ navigation, route }) =>({ headerRight:props =>(<HeaderButton navigation={navigation} nav='Cart' {...props} badgeCount={count}/>)})}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Cart" component={Cart} options={{headerRight:null}}/>
<Stack.Screen name="Search" component={Search} />
</Stack.Navigator>
);
}
export default Route;
headerButton.js
import React, { Component } from "react";
import { View } from 'react-native'
import { Button, Icon, Badge, Text } from 'native-base';
import { Primary, Danger } from '../../assets/color'
export class HeaderButton extends Component{
render(){
return(
<>
<Button rounded transparent onPress={()=>this.props.navigation.push('Cart')}>
<Icon type='MaterialIcons' name='shopping-cart' style={{color:Primary,right:6,top:2}}/>
</Button>
<Text>{this.props.badgeCount}</Text>
</>
);
}
}
home.js
import React, { Component } from "react";
import { View } from 'react-native'
import { Button, Icon, Badge, Text } from 'native-base';
import { Primary, Danger } from '../../assets/color'
export class Home extends Component{
constructor(){
super();
this.state={
count:1
}
}
addToCart=()=>{
var varcount=this.state.count;
varcount=varcount+1;
this.setState({count:varcount})
this.props.onCountChange(this.state.count);
}
render(){
return(
<Button onPress={this.addToCart}>
<Text>Add to cart</Text>
</Button>
);
}
}
Related
I am trying to use navigation in react native, but it gives me an error when I try use a component with navigate (LogIn) with the
<Login/>
tags.
It says that navigate is undified so I passed the navigation as a prop with no success
App.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaView, StyleSheet, Text, View } from 'react-native';
import Login from "./assets/code/Login.js";
import { NavigationContainer, StackActions } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import 'react-native-gesture-handler';
const Stack = createStackNavigator();
export default function App({ navigation }) {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Welcome to dog app, and I hate react"
component={HomePage}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
function HomePage({ navigation }) {
return (
<View style={styles.container}>
<View>
<Text> {""}Welcome to dogappcoolapp app</Text>
</View>
<View style={styles.blue}>
<Login navigate={ navigation } style={styles.blue} />
</View>
</View>
)
}
The error is in this line
<Login navigate={ navigation } style={styles.blue} />
The error is
The LogIn function is in
LogIn.js
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, Script, Alert } from 'react-native';
import { NavigationContainer, StackActions, } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import 'react-native-gesture-handler';
const Stack = createStackNavigator();
export function Login({navigation}) {
if (true)
return (
navigation.navigate('WelcomePage')
);
}
function WelcomePage () {
return (
<View>
<Button title="enter" />
<Text> dog app dog woof-app{"\n\n\n\n\n\n\n\n\n"}OMG!! YOU ARE LOGGED IN! WELCOME!{"\n\n\n\n\n"}</Text>
</View>
);
}
const styles = StyleSheet.create({
blue: {
flex: 2,
backgroundColor: "dodgerblue",
alignItems: 'center',
justifyContent: 'center',
},
});
export default Login;
If I remove all of the navigation prop and tags from the function LogIn, then I can use LogIn as a componnent with <LogIn/>, but not with navigation, I tried usinng it with
navigate={ navigation }
(As it is in the code that I posted)
and I tried without it, I keep getting similar errors.
How can I use LogIn as a component with </> tags while still having navigation component in it?
The logic is correct, in child components, you can pass a navigation prop to get access to navigation, but you are passing your navigation object to a prop called navigate <Login navigate={ navigation } style={styles.blue} />, no wonder it's undefined, you should receive it as navigate in your Login component.
export function Login({navigation}) { //<-- here you have navigation where the prop name that you pass is navigate.
so it should be
export function Login({navigate}) {
...
navigate.navigate('...')
or you should rename your prop to navigation and then your navigation.navigate won't be undefined anymore.
I am making a pokedex, and from the FlatList I would like users to be able to click on a pokemon, and get directed to a detail page of the particular pokemon. However, the navigation.navigate is not working in both class and function based views. I have looked at the documentation and it uses the method I am trying to implement. What is going wrong?
App.js
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import PokedexData from './components/PokedexData';
import PokemonView from './components/PokedexData';
const Stack = createStackNavigator();
export default class App extends React.Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
options={{headerShown: false}}
name="PokedexList"
component={PokedexData}
/>
<Stack.Screen name="PokemonView" component={PokemonView} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
PokedexData.js
import React, {Component} from 'react';
import axios from 'axios';
import {View, FlatList} from 'react-native';
import PodexRow from './PokedexRow';
export default class PokedexRow extends Component {
constructor(props) {
super(props);
this.state = {
pokemon: [],
};
}
componentDidMount() {
this.loadPokemon();
}
loadPokemon = () => {
axios
.get('https://pokeapi.co/api/v2/pokemon?limit=151')
.then((res) => this.setState({pokemon: res.data.results}));
};
renderItem = ({item}) => <PodexRow name={item.name} />;
render() {
return (
<FlatList
data={this.state.pokemon}
renderItem={this.renderItem}
keyExtractor={(item) => item.url}
/>
);
}
}
PokedexRow.js
import {View, StyleSheet, Text, Pressable} from 'react-native';
export default class PokedexRow extends Component {
constructor(props) {
super(props);
}
onPressHandle = () => {
alert(this.props.name);
const {navigate} = this.props.navigation;
};
render() {
return (
<View style={styles.PokedexRowView}>
<Pressable
style={styles.PokedexClickable}
onPress={this.onPressHandle}
android_ripple={{color: 'gray'}}>
<Text style={styles.PokedexRowText}>{this.props.name}</Text>
</Pressable>
</View>
);
}
}
const styles = StyleSheet.create({
/*stles removed for brevity*/
});
Because PokedexRow is not a screen where you get the navigation prop automatically. you can use useNavigation for a functional component to get access to navigation object or pass navigation from screen component to your PokedexRow as a prop.
renderItem = ({item}) => <PodexRow navigation={this.props.navigation} name={item.name} />;
I'm trying to use react-navigate v5 to setup a stacknavigator for four screens. Currently I'm getting this error while trying to run the app:
My App.js:
import React from 'react';
import SafeAreaView from 'react-native-safe-area-view';
import MainStackNavigator from './navigation/Navigator';
import {LocalizationProvider} from './utils/localization/LocalizationContext';
import { NavigationContainer } from '#react-navigation/native';
const App: () => React$Node = () => {
return (
<NavigationContainer>
<LocalizationProvider>
<MainStackNavigator />
</LocalizationProvider>
</NavigationContainer>
);
};
export default App;
My Navigator.js:
import React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {Map} from '../components/Map';
import {HomeScreen} from '../components/HomeScreen';
import {LanguageSettings} from '../components/LanguageSettings';
import {MarkerDetails} from '../components/MarkerDetails';
// import screens
const Stack = createStackNavigator();
function MainStackNavigator() {
return (
<Stack.Navigator
initialRouteName='Home'>
<Stack.Screen
name='Home'
component={HomeScreen}
/>
<Stack.Screen
name='LanguageSettings'
component={LanguageSettings}
/>
<Stack.Screen
name='MainMap'
component={Map}
/>
<Stack.Screen
name='MarkerDetails'
component={MarkerDetails}
/>
</Stack.Navigator>
);
}
export default MainStackNavigator;
And the home screen itself that's generating the error (the other screens do too):
import React, {useContext} from 'react';
import {
View,
Image,
StyleSheet,
Dimensions,
ImageBackground,
Layout,
Text,
Modal,
Button
} from 'react-native';
const { width, height } = Dimensions.get('window');
const frameWidth = width;
const columnWidth = frameWidth / 3;
class HomeScreen extends React.Component {
static navigationOptions = {};
constructor(props) {
super(props);
this.state = {
firstLaunch: null,
condUpdate: null
};
}
///....///
render() {
return(
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
margin: 20,
}}>
</View>
);
}
}
export default HomeScreen;
Not sure what's going on, would appreciate some help. Thanks!
This is happening because of the way you export and import HomeScreen.
If you export default you need to import the entire file. Your fix would be to change the import in the Navigator.js from:
import {HomeScreen} from '../'
to
import HomeScreen from '../'
A time you would use the destructuring import is with a workflow like so:
modules.export = {
a: apple
b: banana
}
----
import { a, b } from './fruits.jsx'
this is a problem with the export
this error occurs when you define the components with default
like this:-
import Home from "./Home";
import Room from "./Room";
import Hall from "./Hall";
export default{Home, Room, Hall};
so you have to define without it like this:-
import Home from "./Home";
import Room from "./Room";
import Hall from "./Hall";
export{Home, Room, Hall};
I want to create navigation for my react native app, but it shows me this error. I don't know how to fix it. At the bottom I have my JS files:
I tried all the codes, for example, I write export className and import {className}
App.js:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack'
import Login from './screens/Login'
import Signup from './screens/Signup'
import Home from './screens/home'
export default class App extends Component {
render() {
return (
<AppRoot />
)
}
}
const Container = createAppContainer({
Login: { screen: Login },
Signup: { screen: Signup },
Home: { screen: Home },
}, {
initialRouteName: 'Login'
})
const AppRoot = createStackNavigator(Container)
Login.js:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Login extends Component {
render() {
return (
<View>
<Text> login </Text>
</View>
)
}
}
Signup.js
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Signup extends Component {
render() {
return (
<View>
<Text> Signup </Text>
</View>
)
}
}
home.js:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Home extends Component {
render() {
return (
<View>
<Text> Home </Text>
</View>
)
}
}
I don't know what is the problem.
It seems you use react-navigation functions in wrong order. First you have to create stack navigator and then create app container with it:
const Container = createStackNavigator({
Login: { screen: Login },
Signup: { screen: Signup },
Home: { screen: Home },
}, {
initialRouteName: 'Login'
})
const AppRoot = createAppContainer(Container)
remove import { createStackNavigator } from 'react-navigation-stack' and use
import { createAppContainer,createStackNavigator } from 'react-navigation';
App.js
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import { createAppContainer, createStackNavigator } from 'react-navigation';
import Login from './screens/Login'
import Signup from './screens/Signup'
import Home from './screens/home'
export default class App extends Component {
render() {
return (
<AppRoot />
)
}
}
let RootStack = createStackNavigator({
Login: Login,
Signup: Signup,
Home: Home,
})
const AppRoot = createAppContainer(RootStack)
Now Navigation props are present across all your screens Login,Signup,Home. To navigate from Login to home for example
Login.js
import React, { Component } from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
export default class Login extends Component {
render() {
return (
<TouchableOpacity onPress={()=>this.props.navigation.navigate('Home')}>
<Text> Home </Text>
</TouchableOpacity>
)
}
}
Hope this helps. Let me know if you have any further queries.
Working with react-native and I get a problem with navigator.
Routes.js
import React from 'react';
import { createStackNavigator, createDrawerNavigator } from 'react-navigation';
import ItemListScreen from '../screens/ItemListScreen';
import ItemDetailsScreen from '../screens/ItemDetailsScreen';
export const RootStack = () => {
return createDrawerNavigator(
{
Home: {
screen: ItemList
},
ItemDetails: {
screen: ItemDetails
}
}
)}
export const ItemList = createStackNavigator({
ItemList: {
screen: ItemListScreen
}
},
{
headerMode: 'none'
});
export const ItemDetails = createStackNavigator({
ItemDetails: {
screen: ItemDetailsScreen
}
},
{
headerMode: 'none'
});
Header.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Header, Body, Text, Icon, Left, Right } from 'native-base';
export default class AppHeader extends Component {
render() {
const headerText = this.props.headerText
return (
<Header>
<Left><Icon name='menu' onPress={()=> this.props.navigation.navigate('DrawerOpen')} /></Left>
<Body style={styles.header}>
<Text style={styles.headerText}>{headerText}</Text>
</Body>
<Right></Right>
</Header>
);
}
}
Index.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Root, Button, Text, Drawer } from 'native-base';
import {RootStack} from './config/Routes';
import Header from './components/Header/Header';
import SideBar from './components/SideBar/SideBar';
export default class Index extends Component {
render() {
const Screen = RootStack();
const { globalContainer } = styles;
return (
<Root style={ globalContainer }>
<Header />
<Screen />
</Root>
)
}
}
The error is:
undefined is not an object (evaluating
'_this2.props.navigation.navigate')
The error is in OnPress() in Header.js
onPress={() => this.props.navigation.navigate('DrawerOpen')
What is the cause of this error? How to solve?
Your navigation object is not defined since you are not providing it the object.
You can include the navigation object using two ways,
Declare the object in the StackNavigator class
Pass navigation props explicitly. For example - in index.js you'll need to change <Header /> to <Header navigation={this.props.navigation} />. So, here you are providing it the necessary proprs in order to execute the navigate action.
EDIT
The actual issue is here,
<Root style={ globalContainer }>
<Header />
<Screen />
</Root>
you are defining your routes later, but calling your Header screen earlier. So precisely, navigation object is undefined in index.js itself.
What you should do is, list index.js in the StackNavigator class as the first object, so it'll be called first. So, your index.js will look something like this.
<Root style={ globalContainer }>
<Header navigation={this.props.navigation} /> //navigation object will be defined here
</Root>
Also, as i see, you have made your DrawerNavigator as your RootStack. I'll like to propose something different, You define a StackNavigator as your root stack, and then include drawer navigation in it.
Something on the lines of -
export const RootStack = createStackNavigator({
Index: //your index.js screen declaration
Drawer: //drawer navigator object
ItemDetails: {
screen: ItemDetailsScreen
}
},
EDIT 2
You'll be not be calling Rootstack in index.js. Your index.js will look something like this.
export default class Index extends Component {
render() {
const { globalContainer } = styles;
return (
<Root style={ globalContainer }>
<Header navigation={this.props.navigation}/>
</Root>
)
}
}
If index.js is your entry file, then you'll have to create a new entry file that calls the RootStack.
Something like entryFile.js
render() { return <RootStack /> }
which will automatically render all your routes and place index.js as your first screen.
Finally solved the issue. My approach has been given below:
Routes.js
import React from 'react';
import { createStackNavigator } from 'react-navigation';
import { Drawer } from './Drawer';
export const App = createStackNavigator(
{
Drawer: {
screen: Drawer
}
},
{
initialRouteName: "Drawer",
headerMode: "none"
}
)
Drawer.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { createDrawerNavigator } from 'react-navigation';
import ItemListScreen from '../screens/ItemListScreen';
import SideBar from '../components/SideBar/SideBar';
export const Drawer = createDrawerNavigator(
{
Home: { screen: ItemListScreen }
},
{
navigationOptions: {
gesturesEnabled: false
},
initialRouteName: "Home",
drawerPosition: 'left',
contentComponent: props => <SideBar {...props} />
}
);
Index.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Button, Text, Drawer } from 'native-base';
import { App } from './config/Routes';
import AppHeader from './components/Header/Header';
export default class Index extends Component {
render() {
const { globalContainer } = styles;
return (
<App style={ globalContainer } navigation={this.props.navigation}></App>
)
}
}
Header.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Header, Body, Text, Icon, Left, Right } from 'native-base';
export default class AppHeader extends Component {
render() {
const {navigation, headerText} = this.props
const {header, text, drawerIcon } = styles
return (
<Header>
<Left>
<Icon name='menu' style={drawerIcon} onPress={()=> navigation.openDrawer()} />
</Left>
<Body style={header}>
<Text style={text}>{headerText}</Text>
</Body>
<Right></Right>
</Header>
);
}
}