undefined is not an object (evaluating '_ref.navigation') React-native navigation error - javascript

How to solve this error in react navigation
I am can't able to navigate another screen from passReg() function,
check bellow my full code on my answer
This is my error

THIS IS MY CODE PLZ SOLVE THIS ERROR
import 'react-native-gesture-handler';
import React,{ useState } from 'react';
import { StyleSheet, Text, SafeAreaView, ScrollView , View,Image,FlatList,RefreshControl,AsyncStorage,TextInput} from 'react-native';
import { TouchableRipple,Button} from 'react-native-paper';
import { useNavigation,NavigationContainer} from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import firebase from 'firebase';
import auth from '#react-native-firebase/auth';
import Reg from './Reg';
const Stack = createStackNavigator();
function passReg({ navigation })
{
navigation.navigate('reg');
}
const PhoneSignIn=()=> {
// If null, no SMS has been sent
const [number, setNumber] = useState(null);
const [confirm, setConfirm] = useState(null);
const [code, setCode] = useState('');
const [flag, setFlag] = useState();
// Handle the button press
async function signInWithPhoneNumber(phoneNumber) {
const addNum = '+91'+phoneNumber;
try{
const confirmation = await auth().signInWithPhoneNumber(addNum);
setConfirm(confirmation);
} catch (error) {
alert(error);
}
}
async function confirmCode() {
try {
await confirm.confirm(code);
if (confirm.confirm(code)) {
AsyncStorage.setItem('mo_num',number);
alert("Congraulation....")
datasend();
}
} catch (error) {
alert(error);
}
}
async function datasend()
{
fetch('https://punjabfoodhub.in/app/reg.php', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'phone_num': number,
})
}).then((response) => response.json())
.then((json) => {
setFlag(json.flag);
if (flag == 'reg') { passReg()}
}).catch((err) => { console.log(err); });
}
if (!confirm) {
return (
<>
<Image
source={require('../assets/cover.png')}
style={styles.image}
/>
<View style={{padding:18}}>
<TextInput
style={styles.input}
placeholder="+91 **********"
onChangeText={num => setNumber(num)}
keyboardType="numeric"
autoCompleteType="tel"
dataDetectorTypes="phoneNumber"
/>
<Button icon="phone" mode="contained" style={styles.btn} onPress={() => passReg()}>
SEND OTP
</Button>
</View>
</>
);
}
return (
<>
<Image
source={require('../assets/cover.png')}
style={styles.image}
/>
<View style={{padding:18}}>
<TextInput
style={styles.input}
maxLength = {6}
onChangeText={text => setCode(text)}
keyboardType="numeric"
placeholder="OTP"
/>
<Button icon="camera" mode="contained" style={styles.btn} onPress={()=> confirmCode()}>
Next
</Button>
<Button mode="text" color="gold" onPress={() => console.log('Pressed')}>
Resend OTP ?
</Button>
</View>
</>
);
}
export default class Login extends React.Component{
constructor(props) {
super(props);
this.state = {
number:null,
otpsend:false,
confirm:null,
otp:null,
};
}
render(){
return(
<ScrollView style={{backgroundColor:'#fff'}}>
<PhoneSignIn/>
<Stack.Navigator headerMode="none">
<Stack.Screen name="main" component={PhoneSignIn} />
<Stack.Screen name="reg" component={Reg} />
</Stack.Navigator>
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FBFCFC', //#FFFAFA
paddingHorizontal:12,
//marginTop: Constants.statusBarHeight,
},
image:{
width:'100%',
height:250
},
input:{
borderRadius:20,
borderWidth: 2,
borderColor:'gold',
paddingHorizontal:20,
fontSize:18
, },
btn:{
borderRadius:20,
backgroundColor:'gold',
paddingVertical:5,
marginTop:8
}
});

I believe this has to do with the deconstruction of the navigation prop.
In the line function passReg({ navigation }), there is probably data that's supposed to be there but is not coming through. I'll check back in when I'm able to find the solution for my exact same problem....

Related

ERROR The action 'NAVIGATE' with payload {...} was not handled by any navigator in React Native

I have implemented AWS custom UI authenctication in my react native app and React navigation to navigate through the different screens.
While implementing the logical conditions to see if the "User is already logged in or not" I have assigned the screen "Home" for logged in user and screen 'Login' for not logged in user it's working fine and navigating as expected but the console is showing this error when clicking on login button.
ERROR The action 'NAVIGATE' with payload {"name":"Home"} was not handled by any navigator.
Here is the Navigation code:
import React, {useEffect, useState} from 'react'
import {ActivityIndicator, Alert, View} from 'react-native';
import HomeScreen from '../screens/HomeScreen';
import LoginScreen from '../screens/LoginScreen';
import RegisterScreen from '../screens/RegisterScreen';
import ConfirmEmailScreen from '../screens/ConfirmEmailScreen';
import ForgotPassword from '../screens/ForgotPassword';
import NewPasswordScreen from '../screens/NewPasswordScreen';
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import {Auth, Hub} from 'aws-amplify';
const Stack = createNativeStackNavigator();
const Navigation = () => {
const [user, setUser] = useState(undefined);
//Checking if user is already logged in or not!
const checkUser = async () => {
try {
const authUser = await Auth.currentAuthenticatedUser({bypassCache: true});
setUser(authUser);
} catch(e) {
setUser(null);
}
};
useEffect(() => {
checkUser();
}, []);
useEffect(() => {
const listener = data => {
if (data.payload.event === 'signIn' || data.payload.event === 'signOut') {
checkUser();
}
}
Hub.listen('auth', listener);
return () => Hub.remove('auth', listener);
}, []);
if (user === undefined) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator/>
</View>
);
}
return (
<NavigationContainer>
<Stack.Navigator>
{/*{If user is logged in navigate him to Homescreen else go throght the Screens based on the user selection */}
{user ? (
<Stack.Screen name='Home' component={HomeScreen}/>
) : (
<>
<Stack.Screen name='Login' component={LoginScreen}/>
<Stack.Screen name='Register' component={RegisterScreen}/>
<Stack.Screen name='ConfirmEmail' component={ConfirmEmailScreen}/>
<Stack.Screen name='ForgotPassword' component={ForgotPassword}/>
<Stack.Screen name='NewPassword' component={NewPasswordScreen}/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
};
export default Navigation;
Here is the Login Screen:
import React, {useState} from 'react'
import { View, Text, Image, StyleSheet, useWindowDimensions, TouchableWithoutFeedback, Keyboard, Alert, KeyboardAvoidingView, ScrollView } from 'react-native'
import Logo from '../../../assets/images/logo-main.png'
import CustomButton from '../../components/CustomButton/CustomButton';
import CustomInput from '../../components/CustomInput/CustomInput';
import { useNavigation } from '#react-navigation/native';
import {Auth} from 'aws-amplify';
import {useForm} from 'react-hook-form';
const LoginScreen = () => {
const [loading, setLoading] = useState(false);
const {height} = useWindowDimensions();
const {control, handleSubmit, formState: {errors}} = useForm();
const navigation = useNavigation();
const onLoginPressed = async (data) => {
if(loading) {
return;
}
setLoading(true);
try {
await Auth.signIn(data.username, data.password);
navigation.navigate('Home');
} catch(e) {
Alert.alert('Opps', e.message)
}
setLoading(false);
};
const onForgotPasswordPressed = () => {
navigation.navigate('ForgotPassword');
}
const onRegisterPressed = () => {
navigation.navigate('Register')
}
return (
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : "height"} style={styles.container}>
<ScrollView contentContainerStyle={{flexGrow:1, justifyContent:'center'}} showsVerticalScrollIndicator={false}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.root}>
<Image source={Logo} style={[styles.logo, {height : height * 0.2}]} resizeMode={'contain'} />
<CustomInput icon='user' name='username' placeholder='Username' control={control} rules={{required: 'Username is required'}} />
<CustomInput icon='lock' name='password' placeholder='Password' control={control} rules={{required: 'Password is required'}} secureTextEntry={true} />
<CustomButton text={loading ? 'Loading...' : 'Login Account'} onPress={handleSubmit(onLoginPressed)} />
<CustomButton text='Forgot Password?' onPress={onForgotPasswordPressed} type='TERTIARY' />
<CustomButton text="Don't have an account? Create one" onPress={onRegisterPressed} type='TERTIARY' />
</View>
</TouchableWithoutFeedback>
</ScrollView>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
root: {
alignItems: 'center',
padding: 20,
},
logo: {
width: 200,
maxWidth: 300,
maxHeight: 300,
},
});
export default LoginScreen;
Issue
At the time you are calling navigation.navigate('Home') there is no screen called in Home in Navigation because of that ternary that checks whether there is a user or not and renders conditionally your screens. That's why React Naviagation is not happy.
Solution
React Navigation's documention tell us that we shouldn't "manually navigate when conditionally rendering screens​". Means you should find a way to call setUser(user) in Login where setUser is the state setter from Navigation component.
To do so we can use a context and for that change Navigation as follow (I added comments where I changed things):
import React, { createContext, useEffect, useState } from "react";
import { ActivityIndicator, View } from "react-native";
import ConfirmEmailScreen from "../screens/ConfirmEmailScreen";
import ForgotPassword from "../screens/ForgotPassword";
import HomeScreen from "../screens/HomeScreen";
import LoginScreen from "../screens/LoginScreen";
import NewPasswordScreen from "../screens/NewPasswordScreen";
import RegisterScreen from "../screens/RegisterScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { Auth, Hub } from "aws-amplify";
const Stack = createNativeStackNavigator();
// Line I added
export const AuthContext = createContext(null);
const Navigation = () => {
const [user, setUser] = useState(undefined);
//Checking if user is already logged in or not!
const checkUser = async () => {
try {
const authUser = await Auth.currentAuthenticatedUser({ bypassCache: true });
setUser(authUser);
} catch (e) {
setUser(null);
}
};
useEffect(() => {
checkUser();
}, []);
useEffect(() => {
const listener = (data) => {
if (data.payload.event === "signIn" || data.payload.event === "signOut") {
checkUser();
}
};
Hub.listen("auth", listener);
return () => Hub.remove("auth", listener);
}, []);
if (user === undefined) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator />
</View>
);
}
return (
// Wrapper I added
<AuthContext.Provider value={{ user, setUser }}>
<NavigationContainer>
<Stack.Navigator>
{/*{If user is logged in navigate him to Homescreen else go throght the Screens based on the user selection */}
{user ? (
<Stack.Screen name="Home" component={HomeScreen} />
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="ConfirmEmail" component={ConfirmEmailScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPassword} />
<Stack.Screen name="NewPassword" component={NewPasswordScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
);
};
export default Navigation;
Consume AuthContext from Navigation in Login so you are able to call setUser after login, like below (I added comments where I changed thing):
import { useNavigation } from "#react-navigation/native";
import React, { useContext, useState } from "react";
import {
Alert,
Image,
Keyboard,
KeyboardAvoidingView,
ScrollView,
StyleSheet,
TouchableWithoutFeedback,
useWindowDimensions,
View,
} from "react-native";
import Logo from "../../../assets/images/logo-main.png";
import CustomButton from "../../components/CustomButton/CustomButton";
import CustomInput from "../../components/CustomInput/CustomInput";
import { Auth } from "aws-amplify";
import { useForm } from "react-hook-form";
// Line I added
import {AuthContext} from "./Navigation" // ⚠️ use the correct path
const LoginScreen = () => {
// Line I added
const { setUser } = useContext(AuthContext);
const [loading, setLoading] = useState(false);
const { height } = useWindowDimensions();
const {
control,
handleSubmit,
formState: { errors },
} = useForm();
const navigation = useNavigation();
const onLoginPressed = async (data) => {
if (loading) {
return;
}
setLoading(true);
try {
const user = await Auth.signIn(data.username, data.password);
// Line I added
setUser(user);
} catch (e) {
Alert.alert("Opps", e.message);
}
setLoading(false);
};
const onForgotPasswordPressed = () => {
navigation.navigate("ForgotPassword");
};
const onRegisterPressed = () => {
navigation.navigate("Register");
};
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.container}
>
<ScrollView
contentContainerStyle={{ flexGrow: 1, justifyContent: "center" }}
showsVerticalScrollIndicator={false}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.root}>
<Image
source={Logo}
style={[styles.logo, { height: height * 0.2 }]}
resizeMode={"contain"}
/>
<CustomInput
icon="user"
name="username"
placeholder="Username"
control={control}
rules={{ required: "Username is required" }}
/>
<CustomInput
icon="lock"
name="password"
placeholder="Password"
control={control}
rules={{ required: "Password is required" }}
secureTextEntry={true}
/>
<CustomButton
text={loading ? "Loading..." : "Login Account"}
onPress={handleSubmit(onLoginPressed)}
/>
<CustomButton
text="Forgot Password?"
onPress={onForgotPasswordPressed}
type="TERTIARY"
/>
<CustomButton
text="Don't have an account? Create one"
onPress={onRegisterPressed}
type="TERTIARY"
/>
</View>
</TouchableWithoutFeedback>
</ScrollView>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
root: {
alignItems: "center",
padding: 20,
},
logo: {
width: 200,
maxWidth: 300,
maxHeight: 300,
},
});

Chat Messages screen doesn't update message screen after post message using expo-react native-typescript

I'm trying to learning about chat app using expo-react native-typescript. What im doing so far is like below :
ChatRoomScreen.tsx
import React, { useState, useRef, useEffect } from 'react';
import { StyleSheet, Text, View, FlatList, SafeAreaView, ActivityIndicator } from 'react-native'
import { useRoute, useNavigation } from '#react-navigation/core'
import Message from '../components/Message'
import MessageInput from '../components/MessageInput'
// api client
import axios from 'axios';
const ChatRoomScreen = () => {
const route = useRoute()
const mounted = useRef(true);
const roomID = route.params?.id
const user = route.params?.user
const isMe = route.params?.isMe
const [message, setMessage] = useState();
//AxiosRequest
//get chats
const fetchMessages = async () =>{
axios.get('https://mylaravelAPI.com/api/get/'+roomID)
.then(function (response) {
// handle success
const result = response.data.message.reverse();
{setMessage(result)}
})
}
useEffect(() => {
fetchMessages()
},[])
return (
<SafeAreaView style={styles.page}>
<FlatList
data={message}
//Send params to Message
renderItem={({item}) => <Message message={item} roomID={roomID}/> }
inverted
/>
<MessageInput
//Send params to MessageInput
id={route.params?.id}
receiveID={route.params?.user}
userID={route.params?.isMe}
/>
</SafeAreaView>
)
}
export default ChatRoomScreen
Message.tsx
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
const blue = '#3777f0'
const grey = 'lightgrey'
const myID = '1'
const Message = ({ message, roomID }) => {
const isMe = message.user.id == myID
const roomId = roomID
return (
<View style={[
styles.container, isMe ? styles.rightContainer : styles.leftContainer]}
>
<Text style={{ color: isMe ? 'black' : 'white' }}>{message.content}</Text>
</View>
)
}
export default Message
MessageInput.tsx
import React, { useState, useEffect } from 'react'
import { StyleSheet, Text, View, TextInput, Pressable } from 'react-native'
import { SimpleLineIcons, Feather, MaterialCommunityIcons, AntDesign, Ionicons } from '#expo/vector-icons'
import MessageComponent from "../Message";
// api client
import axios from 'axios';
const MessageInput = ({id, receiveID, userID}) => {
const [message, setMessage] = useState()
const chatroom = id
const senderUserID = userID.id
const receiveUserID = receiveID.id
//Action
//save message
const saveMessage = () => {
axios({
method: 'post',
url: 'https://mylaravelAPI.com/api/post',
headers: {
'content-type': 'application/json',
},
data: JSON.stringify({
"content": message,
"userID": senderUserID,
"replyToID": receiveUserID
})
});
setMessage('')
}
//update message
const updateMessage = () => {
console.log('updateMessage')
}
//OnPress
const onPress2 = () => {
if (chatroom === null) {
{saveMessage()}
}else{
{updateMessage()}
}
}
const onPress = () => {
// console.log(message)
}
return (
<View style={styles.root}>
<View style={styles.inputContainer}>
<SimpleLineIcons name='emotsmile' size={24} color='#595959' style={styles.icon}/>
<TextInput
style={styles.input}
value={message}
onChangeText={setMessage}
placeholder="Signal message..."
/>
<Feather name='camera' size={24} color='#595959' style={styles.icon}/>
<MaterialCommunityIcons name='microphone-outline' size={24} color='#595959' style={styles.icon}/>
</View>
{/* <Pressable onPress={onPress} style={styles.buttonContainer}>
{message ? <Ionicons name="send" size={18} color="white" /> : <AntDesign name='plus' size={24} color='white' />}
</Pressable> */}
<View onPress={onPress} style={styles.buttonContainer}>
{message ?
<Pressable
onPress={onPress2}>
<Ionicons name="send" size={18} color="white" />
</Pressable> :
<Pressable
onPress={onPress}>
<AntDesign name='plus' size={24} color='white' />
</Pressable>
}
</View>
</View>
)
}
export default MessageInput
Everything is working except the message not update or shows ini realtime. It's will show only when i go back to Welcome screen and open the chat/room again... please help me.. thanks

TypeError: undefined is not an object (evaluating 'navigation.replace')

MY login page
import React, { useState } from 'react'
import { TouchableOpacity, StyleSheet, View, ImageBackground } from 'react-native'
import { Text } from 'react-native-paper'
import Logo from '../Component/Logo'
import Header from '../Component/Header'
import Button from '../Component/Button'
import TextInput from '../Component/Inputtext'
import BackButton from '../Component/Backbutton'
import { theme } from '../core/theme'
import { emailValidator } from '../Component/emailval'
import { passwordValidator } from '../Component/Passwordval'
export default function LoginScreen({ navigation }) {
const [email, setEmail] = useState({ value: '', error: '' })
const [password, setPassword] = useState({ value: '', error: '' })
const onLoginPressed = () => {
const emailError = emailValidator(email.value)
const passwordError = passwordValidator(password.value)
if (emailError || passwordError) {
setEmail({ ...email, error: emailError })
setPassword({ ...password, error: passwordError })
return
}
navigation.reset({
index: 0,
routes: [{ name: 'Dashboard' }],
})
}
return (
<ImageBackground style={styles.image} source={require('../imgs/back.png') }>
<View>
<BackButton />
<Logo />
<Header style={styles.header}>Welcome back.</Header>
<TextInput
label="Email"
returnKeyType="next"
value={email.value}
onChangeText={(text) => setEmail({ value: text, error: '' })}
error={!!email.error}
errorText={email.error}
autoCapitalize="none"
autoCompleteType="email"
textContentType="emailAddress"
keyboardType="email-address"
style={styles.textmail}
/>
<TextInput
label="Password"
returnKeyType="done"
value={password.value}
onChangeText={(text) => setPassword({ value: text, error: '' })}
error={!!password.error}
errorText={password.error}
secureTextEntry
style={styles.textmail}
/>
<View style={styles.forgotPassword}>
<TouchableOpacity
onPress={() => navigation.navigate('ResetPasswordScreen')}
>
<Text style={styles.forgot}>Forgot your password?</Text>
</TouchableOpacity>
</View>
<Button mode="contained" onPress={onLoginPressed} style={styles.login}>
Login
</Button>
<View style={styles.row}>
<Text>Don’t have an account? </Text>
<TouchableOpacity onPress={() => navigation.replace('login')}>
<Text style={styles.link}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
)
}
const styles = StyleSheet.create({
forgotPassword: {
width: '100%',
alignItems: 'flex-end',
marginBottom: 24,
},
row: {
flexDirection: 'row',
marginTop: 4,
},
forgot: {
fontSize: 13,
color: '#414757',
},
link: {
fontWeight: 'bold',
color: '#560CCE',
},
header: {
fontSize: 21,
color: '#560CCE',
fontWeight: 'bold',
paddingVertical: 12,
},
image: {
width:'100%',
height: '100%',
},
textmail:{
backgroundColor:"#ffffff",
width:"90%",
alignSelf:'center',
borderRadius:40,
},
login:{
width:"70%"
}
})
App js::
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import OnboardingScreen from './Component/Onboardingscreen';
import LoginScreen from './Component/Loginscreen';
import Forgotpass from './Component/Forgotpassword';
import RegisterScreen from './Component/SignupScreen';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useEffect } from 'react';
const AppStack = createStackNavigator();
const App =() => {
const [isFirstLaunch, setIsFirstLaunch,] = React.useState(null);
useEffect(() => {
AsyncStorage.getItem('alreadyLaunched').then(value => {
if(value == null) {
AsyncStorage.setItem('alreadyLaunched','true');
setIsFirstLaunch(true);
} else {
setIsFirstLaunch(false);
}
});
}, []);
if (isFirstLaunch == null) {
return null;
} else if ( isFirstLaunch == true ){
return (
<NavigationContainer>
<AppStack.Navigator
headerMode='none'
>
<AppStack.Screen name="OnboardingScreen" component={OnboardingScreen}/>
<AppStack.Screen name='login' component={LoginScreen} />
<AppStack.Screen name="RegisterScreen" component={RegisterScreen} />
<AppStack.Screen name="ResetPasswordScreen" component={Forgotpass} />
</AppStack.Navigator>
</NavigationContainer>
);
} else {
return <LoginScreen />;
}
}
export default App;
Error occur while i pressing "forgot password" and "signup" ,
all dependency is addad ,
it shows onpress error and i added error screenshot also there are following below,
ERROR TypeError: undefined is not an object (evaluating 'navigation.replace')
ERROR TypeError: undefined is not an object (evaluating 'navigation.replace')
Try using the useNavigation() hook:
import { useNavigation } from '#react-navigation/native';
export default function LoginScreen() {
const navigation = useNavigation();
return (
...
<TouchableOpacity onPress={() => navigation.replace('login')}>
<Text style={styles.link}>Sign up</Text>
</TouchableOpacity>
...
);
}
Single data in a array is deleted in api data so it's show
null is a not an object
Solution:give the absent value = null;

Loading spinner as well as fetched products from firebase isn't showing until I refresh the screen in react native

I am using ActivityIndicator for showing the loading screen while my dispatch function dispatches the action and fetches the products from the firebase and renders it on my app screens But this is not happening. My app is showing products that are in store as dummy data and if I refresh the screen then it shows the data from firebase but not the loading spinner to show that loading is true.
ProductOverviewScreen.js:
import React, { useState, useEffect, useCallback } from "react";
import {
FlatList,
View,
Button,
Text,
StyleSheet,
Platform,
ActivityIndicator,
} from "react-native";
import { useSelector, useDispatch } from "react-redux";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import ProductItem from "../../components/shop/ProductItem";
import * as cartActions from "../../store/actions/cart";
import * as productActions from "../../store/actions/products";
import CustomHeaderButton from "../../components/UI/HeaderButton";
import Colors from "../../constants/Colors";
const ProductOverviewScreen = (props) => {
const [IsLoading, setIsLoading] = useState();
const [IsRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState();
const products = useSelector((state) => state.products.availableProducts);
const dispatch = useDispatch();
const loadedProducts = useCallback(() => {
setError(null);
setIsRefreshing(true);
dispatch(productActions.fetchProducts())
.then(setIsLoading(false))
.catch((err) => {
setError(err.message);
});
setIsRefreshing(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
const willFocusSub = props.navigation.addListener(
"willFocus",
loadedProducts
);
return () => {
willFocusSub.remove();
};
}, [loadedProducts]);
useEffect(() => {
const loading = async () => {
setIsLoading(true);
await loadedProducts();
setIsLoading(false);
};
}, [dispatch, loadedProducts]);
const selectItemHandler = (id, title) => {
props.navigation.navigate("ProductDetail", {
productId: id,
productTitle: title,
});
};
const addToCartHandler = async (itemData) => {
setIsLoading(true);
await dispatch(cartActions.addToCart(itemData.item));
setIsLoading(false);
};
if (error) {
return (
<View style={styles.loadingSpiner}>
<Text>An Error occurred! </Text>
<Button
title="Try Again"
onPress={loadedProducts}
color={Colors.primary}
/>
</View>
);
}
if (IsLoading) {
return (
<View style={styles.loadingSpiner}>
<ActivityIndicator size="large" color={Colors.primary} />
</View>
);
}
if (!IsLoading && products.length === 0) {
return (
<View style={styles.loadingSpiner}>
<Text>No Product Found!</Text>
</View>
);
}
return (
<FlatList
data={products}
onRefresh={loadedProducts}
refreshing={IsRefreshing}
renderItem={(itemData) => (
<ProductItem
image={itemData.item.imageUrl}
title={itemData.item.title}
price={itemData.item.price}
onSelect={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
>
<Button
color={Colors.primary}
title="View Details"
onPress={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
/>
{IsLoading ? (
<ActivityIndicator size="small" color={Colors.primary} />
) : (
<Button
color={Colors.primary}
title="To Cart"
onPress={() => {
addToCartHandler(itemData);
}}
/>
)}
</ProductItem>
)}
/>
);
};
ProductOverviewScreen.navigationOptions = (navigationData) => {
return {
headerTitle: "All Products",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Menu"
iconName={Platform.OS === "android" ? "md-menu" : "ios-menu"}
color={Platform.OS === "android" ? Colors.primary : "white"}
onPress={() => {
navigationData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Cart"
iconName={Platform.OS === "android" ? "md-cart" : "ios-cart"}
onPress={() => {
navigationData.navigation.navigate("Cart");
}}
/>
</HeaderButtons>
),
};
};
const styles = StyleSheet.create({
loadingSpiner: {
flex: 1,
justifyContent: "center",
alignItems: "center",
opacity: 1,
},
});
export default ProductOverviewScreen;
I have also checked on both emulators IOS and android also on my real device. If I open the app on my real device then instantly app renders the data from the firebase but doesn't show a loading spinner.
In useEffect If I try to add dependency loading which costs async code and a function which fetches the data from firebase then it shows an error saying Can't find variable: loading.
Please making loadedProducts from sync to async

React-Native : Passing variable onClick to handler in different file

I am a new React-Native programmer . I am trying to create a login page but I am not sure how to pass some parameters to a handler function that is located in different files.
I am trying to pass the variable email and password in SignIn.js to onVerify in Auth.js during onClick() button
SignIn.js
import React from "react";
import { View } from "react-native";
import { Card, Button, FormLabel, FormInput } from "react-native-elements";
import { onVerify } from "../auth";
import { onSignIn } from "../auth";
export default class SignIn extends React.Component{
constructor(props) {
super(props);
const {navigation} = this.props.navigation;
this.state ={
email : "huzaifah1011#gmail.com",
password : "12345",
name : "",
logged : false
}
}
render(){
return(
<View style={{ paddingVertical: 20 }}>
<Card>
<FormLabel>Email</FormLabel>
<FormInput placeholder="Email address..." />
<FormLabel>Password</FormLabel>
<FormInput secureTextEntry placeholder="Password..." />
<Button
buttonStyle={{ marginTop: 20 }}
backgroundColor="#03A9F4"
title="SIGN IN"
onPress={() => {onVerify(this.state.email,this.state.password);}}
// {()=> this.onVerify()}
/>
</Card>
</View>
);
}
}
and for the onClick function which is the onVerify is located in auth.js
import { AsyncStorage } from "react-native";
export const USER_KEY = "auth-demo-key";
export const onSignIn = () => AsyncStorage.setItem(USER_KEY, "true");
export const onSignOut = () => AsyncStorage.removeItem(USER_KEY);
export const onVerify = (email,password) => {
fetch('xxx',
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'email=' + this.email + '&password=' + this.password
})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.status == '200') {
onSignIn();
() => navigation.navigate("SignedIn")
}
console.log(responseJson)
})
.catch((error) => {
console.error(error);
});}
Add one local function in SignIn Component and from that function call onVerify of auth.
export default class SignIn extends React.Component{
//add local function
onVerify = ()=>{
onVerify(this.state.email,this.state.password);
}
render(){
return(
<View style={{ paddingVertical: 20 }}>
<Card>
//....
<Button
buttonStyle={{ marginTop: 20 }}
backgroundColor="#03A9F4"
title="SIGN IN"
onPress={() => this.onVerify()} //call the local function
/>
</Card>
</View>
);
}
}

Categories