Why the Expo Go exit when I refresh my app on this eidt screen only? - javascript

I'm using Expo Go app on my device to run my app and everything is working properly except edit screen when I want to refresh Expo Go app the Expo shut down by itself only on edit screen and on other screens, I can smoothly refresh without exiting from the expo go app.
Here is my Edit screen code:
import firebase from "firebase";
import {db,auth} from '../../firebase'
const EditProfile=({navigation})=>{
const sheetRef = React.createRef(null);
const animated = new Animated.Value(1);
const [image, setImage] = useState(null);
const [uploading,setUploading] = useState(false)
const [userData, setUserData] = useState(null);
React.useEffect(()=>{
const getUserData = async()=>{
db.collection("users")
.doc(auth.currentUser?.uid)
.get()
.then(snap => {
setUserData(snap.data());
});
}
getUserData();
},[])
const updateProfile = async()=>{
let imgUrl = await uploadImage();
if(imgUrl == null && userData.userImg){
imgUrl = userData.userImg
}
db.collection("users")
.doc(auth.currentUser.uid)
.set({
name: userData.name,
email: userData.email,
phone: userData.phone,
address: userData.address,
userImg:userData.imgUrl
})
}
{/*upload Image to firebase sotrage*/}
const uploadImage = async ()=>{
if(image == null){
return "";
}
const blob = await new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.onload = function (){
resolve(xhr.response)
};
xhr.onerror = function (){
reject( new TypeError("Network request failed"))
};
xhr.responseType = "blob"
xhr.open("GET",image,true)
xhr.send(null)
});
const ref = firebase.storage().ref().child("images/" + new Date().toISOString())
const snapshot = ref.put(blob)
snapshot.on(
firebase.storage.TaskEvent.STATE_CHANGED,
()=>{
setUploading(true)
},
(error)=>{
setUploading(false)
console.log(error)
blob.close();
return ;
},
()=>{
snapshot.snapshot.ref.getDownloadURL().then((url)=>{
setUserData({...userData, imgUrl: url})
setUploading(false);
// Alert.alert('Profile Updated', 'You profile Updated Successfully..!')
console.log('donwload:', url)
blob.close()
return null
})
}
)
}
{/*Render COntent for Bottom Sheet*/}
const renderContent=()=>{
return(
<View style={style.panel}>
<View>
<Text>Upload Photo</Text>
<Text>Choose Your Profile Picture</Text>
</View>
<AppButton
label='Take Photo'
onPress={OpenCamera}
/>
<AppButton
label='Choose from Library'
onPress={pickImage}
/>
<AppButton
label='Cancel'
onPress={() => sheetRef.current.snapTo(1)}
/>
</View>
)
}
{/*Render Header For Bottom Sheet*/}
const renderHeader=()=>{
return(
<View style={style.header}>
<View style={style.panelHeader}>
<View style={style.panelHandle} />
</View>
</View>
)
}
{/*Pick Image Function*/}
const pickImage = async () => {
const {granted} = await ImagePicker.requestMediaLibraryPermissionsAsync()
if (!granted){
Alert.alert("Donate", 'You need to enable permission from the settings to access the camera..!')
return;
}
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
onPress:sheetRef.current.snapTo(1)
});
console.log(result);
if (!result.canceled) {
setImage(result.assets[0].uri);
}
};
{/*Open Camera to take Pic*/}
const OpenCamera = async () => {
//permissions request is necessary for Openning Camera
const {granted} = await ImagePicker.requestCameraPermissionsAsync()
if (!granted){
Alert.alert("Donation", 'You need to enable permission from the settings to access the camera..!')
return ;
}
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
onPress:sheetRef.current.snapTo(1)
});
console.log(result);
if (!result.cancelled) {
setImage(result.uri);
}
};
I really don't know why only on Edit Profile screen the Expo Go app exit when I refresh my app on it, but when I do refresh my app on different screen like home screen the Expo Go app refreshing smoothly without exit from the app or shut it down and open it again. Any idea about this issue please do help me thank you.

Related

How can I upload multiple Images to AWS using Expo Image Picker

Based on the example given in the documentation of expo image picker I'm trying to upload multiple images to AWS Amplify. In the example given on github only one picture is being worked with. Setting the allowsMultipleSelection prop to true makes it possible to pick multiple images but though I've been tinkering with the code to suit it to my need I can't seem to get it.
Here's what I'm doing
import { Amplify, Auth, Storage } from "aws-amplify";
import * as Clipboard from "expo-clipboard";
import * as ImagePicker from "expo-image-picker";
import { useState } from "react";
import { Button, Image, Text, View } from "react-native";
import awsconfig from "../aws-exports";
Amplify.configure(awsconfig);
const UploadImageAWS = () => {
const [image, setImage] = useState([]);
const [percentage, setPercentage] = useState(0);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images",
aspect: [4, 3],
quality: 1,
allowsMultipleSelection: true,
});
this.handleImagePicked(result);
};
handleImagePicked = async (pickerResult) => {
try {
if (!pickerResult.canceled) {
pickerResult.forEach(async (element) => {
setPercentage(0);
const img = await fetchImageFromUri(element.uri);
const uploadUrl = await uploadImage(img.name, img);
downloadImage(uploadUrl);
});
}
} catch (e) {
alert("Upload failed");
}
};
uploadImage = (filename, img) => {
Auth.currentCredentials();
return Storage.put(filename, img, {
level: "public",
contentType: "image/jpeg",
progressCallback(progress) {
setLoading(progress);
},
})
.then((response) => {
return response.key;
})
.catch((error) => {
return error.response;
});
};
const setLoading = (progress) => {
const calculated = parseInt((progress.loaded / progress.total) * 100);
updatePercentage(calculated); // due to s3 put function scoped
};
const updatePercentage = (number) => {
setPercentage(number);
};
downloadImage = (uri) => {
Storage.get(uri)
.then((result) => setImage(result))
.catch((err) => console.log(err));
};
const fetchImageFromUri = async (uri) => {
const response = await fetch(uri);
const blob = await response.blob();
return blob;
};
const copyToClipboard = () => {
Clipboard.setString(image);
alert("Copied image URL to clipboard");
};
return (
<View style={styles.container}>
<Text style={styles.title}>AWS Storage Upload Demo</Text>
{percentage !== 0 && <Text style={styles.percentage}>{percentage}%</Text>}
{image &&
image.map((img) => (
<View>
<Text style={styles.result} onPress={copyToClipboard}>
<Image
source={{ uri: img }}
style={{ width: 250, height: 250 }}
/>
</Text>
<Text style={styles.info}>Long press to copy the image url</Text>
</View>
))}
<Button onPress={pickImage} title="Pick an image from camera roll" />
</View>
);
};
export default UploadImageAWS;
Running a loop on the handleImagePicked function then having a random name being generated for each picture solved the problem. Here's what the code looks like
imports
import { v4 as uuidv4 } from "uuid";
import * as ImagePicker from "expo-image-picker";
methods logic
let imagesArray = [];
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images",
aspect: [4, 3],
quality: 1,
allowsMultipleSelection: true,
});
result.assets.forEach((image) => handleImagePicked(image));
};
const handleImagePicked = async (pickerResult) => {
const imageName = uuidv4();
try {
if (!pickerResult.canceled) {
const img = await fetchImageFromUri(pickerResult.uri);
const uploadUrl = await uploadImage(imageName, img);
console.log("upload url = ", uploadUrl);
downloadImage(uploadUrl);
}
} catch (e) {
console.log("Upload failed", e.message);
}
};
const uploadImage = async (filename, img) => {
Auth.currentCredentials();
return Storage.put(filename, img, {
level: "public",
contentType: "image/jpeg",
})
.then((response) => {
return response.key;
})
.catch((error) => {
console.log(error);
return error.response;
});
};
const downloadImage = (uri) => {
Storage.get(uri)
.then((result) => {
setImages(result);
imagesArray.push(result);
})
.catch((err) => console.log(err));
};
const fetchImageFromUri = async (uri) => {
const response = await fetch(uri);
const blob = await response.blob();
// console.log("blob of URI : " + JSON.stringify(blob));
return blob;
};
Images display
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={imagesArray}
renderItem={({ item }) => (
<Image
source={{ uri: item }}
style={{
height: 75,
width: 75,
borderRadius: 10,
marginHorizontal: 10,
resizeMode: "contain",
}}
/>
)}
/>

React Native why does the app crash when sending photo to API

My app keeps crashing when user tries to send photo from camera to API. There were no problem in the android emulator but it crashes on my physical device (Galaxy A30). The console.log doesn't show anything when I used it on the emulator. There were no problem submitting from image gallery but when submitting from the camera, it crashes.
import React, {useState, useContext} from 'react';
import {ScrollView, View, Text, TextInput, TouchableOpacity, Alert} from 'react-native';
import { AuthContext } from '../Context/AuthContext';
import { URLs } from '../constants/links';
import * as ImagePicker from 'expo-image-picker';
import axios from 'axios';
import * as Permissions from "expo-permissions";
import { CAMERA } from "expo-permissions";
const MyScreen = ({navigation}) => {
const { myToken } = useContext(AuthContext)
const [allImage, setAllImage] = React.useState([]);
const [pickedImage, setPickedImage] = useState("");
const [fileName, setFileName] = React.useState("");
const formdata = new FormData();
const cameraPermission = async () => {
const result = await Permissions.askAsync(CAMERA);
if (result.status != "granted") {
Alert.alert(
"Insufficient Permission",
"You need to grant camera permission to use this app",
[{ text: "Okay" }]
);
return true;
}
return true;
};
const useCamera = async () => {
const hasPermissions = await cameraPermission();
if (!hasPermissions) {
return;
}
if(allImage.length < 4){
let result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
quality: 0.5,
});
if (!result.cancelled) {
const name = result.uri.split('/').pop();
let match = /\.(\w+)$/.exec(name);
let type = match ? `image/${match[1]}` : `image`;
let newFile = {
uri: result.uri,
type: type,
name: name
}
setAllImage(newFile)
setPickedImage(result.uri)
if (!pickedImage && allImage.length === 0) {
setAllImage([newFile]);
setFileName("Photo 1")
}else {
setAllImage([...allImage, newFile]);
setFileName(fileName + ", Photo " + (allImage.length + 1))
}
}
} else {
Alert.alert("Image", "You have reach the image upload limit");
}
};
const fetchData = () => {
const abortCont = new AbortController();
allImage.forEach((file) => {
formdata.append('files[]', file);
});
axios({
method: 'post',
url: URLs,
headers: {
Accept: "application/json",
Authorization: myToken,
'Content-Type': "multipart/form-data",
},
data: formdata,
signal: abortCont.signal,
}).then(function (result) {
if(result.data.message === "Successfully added") {
Alert.alert("Upload Successufull", result.data.message);
navigation.goBack()
}
}).catch(function (error) {
Alert.alert("Error", error);
formdata = new FormData();
});
return () => abortCont.abort();
}
return (
<ScrollView>
<View>
<View>
<Text>Attach Receipt File</Text>
<View>
<TextInput
editable={false}
placeholder="Select files.."
value={fileName}
/>
</View>
<View>
<TouchableOpacity activeOpacity={0.8} onPress={useCamera}>
<Text>Camera</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity activeOpacity={0.9} onPress={fetchData}>
<Text>Submit</Text>
</TouchableOpacity>
</View>
</View>
</View>
</ScrollView>
);
}
export default MyScreen;
I still don't know the reason why the app crash when user send photo taken from camera but I found a solution. I change from using camera from expo-permission to Camera from expo-camera. This is the docs: https://docs.expo.dev/versions/latest/sdk/camera/#cameracapturedpicture

React Native logout functionality not working properly

Hy, I'm creating the react-native app in native-cli. I'm trying first-time navigation 5. when I do the login I receive the Token and store it in AsyncStorage but need to reload the app to move toward the dashboard so to solve this I used the useContext and its working fine but now the issue is that when I login the app and move around it and then press the logout button it works nicely but when I login the app surf the app and then press the back button go to the home screen of mobile without logout then again when I come back to the app and press log out it clear the AsyncStorge but not log out the app and I need to refresh then it goes back to the login screen.
App.js
const App = () => {
const [user, setUser] = useState(false)
const [log, setLog] = useState(0)
const [role, setRole] = useState('seller')
//console.log('App.js-Start')
console.log("app_User:",user);
console.log("app_log:",log);
useEffect(()=>{
getKeysData(dataKeys)
},[])
const dataKeys = ['token', 'super_user_status', 'isLoggedIn'];
const getKeysData = async (keys) => {
const stores = await AsyncStorage.multiGet(keys);
//console.log(stores)
// const aData = stores.map(([key, value]) => ({ [key]: value }))
const aData = await Promise.all(stores.map(([key, value]) => ({[key]: value})))
const token = aData[0]['token']
const super_user_status = aData[1]['super_user_status']
const isLoggedIn = aData[2]['isLoggedIn']
console.log('token',token)
console.log('SuperUser', super_user_status)
console.log('Log',isLoggedIn)
//setUser(isLoggedIn)
if(isLoggedIn == 1){
setLog(1)
}
}
return (
<NavigationContainer>
<LoginContext.Provider value={{user,setUser}} >
{ user == false && log==0 ?
<AuthStackScreen />
:
<BuyerDashboardStackScreens />
}
</LoginContext.Provider>
</NavigationContainer>
);
};
export default App;
Login
await axios({
method: 'POST',
url: api + 'login/',
data: login_Credentials,
headers: { 'Content-Type': 'multipart/form-data' }
}).then(async function (response) {
if (response.data.success == true) {
const token = response.data.token.toString();
const super_user_status = response.data.super_user_status.toString();
const isLoggedIn = "1"
//console.log('Logged In and set Storgae')
await AsyncStorage.multiSet([['isLoggedIn',isLoggedIn],['token', token], ['super_user_status', super_user_status]])
setUser(true)
setEmail('')
setPassword('')
setPress(false)
}
logout
const logOut = () => {
AsyncStorage.clear();
setUser(false);
};

React-native unidentified is not an object

When I dispatch my delete action to Redux I am getting the error unidentified is not an object evaluating selectedUser.imageUri Everything is being loaded from a server and I know the delete action works as it deletes the object from the server however I get this error and the screen only updates when I reload the application. Please can someone help me I really need your help. Thank you so much in advance!!!I am even checking to see if there is no object in the selecetedUser array then render an image called nothing.png
This is my code where I am seeing the error
const Viewer = (props) => {
const userID = props.navigation.getParam('id')
//Nothing is just a picture when there are no images
import nothing from './Images/nothing.png'
const selectedUser = useSelector(state => state.user.user.find(user => user.id === userID))
const cBimageUri = {uri: selectedUser.imageUri }
const checkImage = cBimageUri.length === 0? nothing : cBimageUri
const cBimageUri = {uri: selectedUser.imageUri }
const deleteCb = useCallback(() =>{
dispatch(deleteUser(userID))
props.navigation.goBack()
},[userID])
useEffect(() => {
props.navigation.setParams({deleteCb: deleteCb})
},[deleteCb])
return (
<ScrollView style={{backgroundColor: 'white'}}>
<Image source={checkImage} style={styles.image}/>
<Text style={styles.name}>{selectedCookBook.name}</Text>
</ScrollView>
)
}
export default Viewer
Redux reducer
import { CREATE_USER, DELETE_USER } from '../actions/account'
const initialState = {
account: [],
}
const USerReducer = (state=initialState, action) =>{
switch(action.type){
case CREATE_USER:
const newUser = new MyUser(
action.userData.id,
action.userData.name,
action.userData.image,
)
return { ...state, user: state.account.concat(newUser)}
case DELETE_USER:
const filteredItems = state.account.filter(cb => cb.id !== action.deleteCb)
return {account: filteredItems }
default:
return state
}
}
export default USerReducer
Redux action
export const DELETE_COOKBOOK = 'CLEAR'
export const deleteCookbook = (deleteCb) => {
return {type: DELETE_COOKBOOK, deleteCb: deleteCb}
}
console logging selectedUser
[
Object {
"id": 1595444079901,
"val": "Veveve",
},
name: John Snow,
imageUri: 'file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Frn-first-app-e648c632-2715-4169-abf3-e0cdbe2ac7d5/ImagePicker/461b63af-a908-47e9-8841-d5d8f2c4eb67.jpg
file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Frn-first-app-e648c632-2715-4169-abf3-e0cdbe2ac7d5/ImagePicker/461b63af-a908-47e9-8841-d5d8f2c4eb67.jpg'
}
]
Try to change follow
const Viewer = (props) => {
const userID = props.navigation.getParam('id')
//Nothing is just a picture when there are no images
import nothing from './Images/nothing.png'
const selectedUser = useSelector(state => state.user.user.find(user => user.id === userID))
const cBimageUri = selectedUser.imageUri // --> changed it
const checkImage = cBimageUri.length === 0? nothing : cBimageUri
//const cBimageUri = {uri: selectedUser.imageUri } // is it a right row? just repeat previous
const deleteCb = useCallback(() =>{
dispatch(deleteUser(userID))
props.navigation.goBack()
},[userID])
useEffect(() => {
props.navigation.setParams({deleteCb: deleteCb})
},[deleteCb])
return (
<ScrollView style={{backgroundColor: 'white'}}>
<Image source={{uri: checkImage}} style={styles.image}/> // --> changed it. Not sure about it, if it's not working check below link
<Text style={styles.name}>{selectedCookBook.name}</Text>
</ScrollView>
)
}
export default Viewer
this link https://stackoverflow.com/questions/50249353/uri-vs-url-in-react-native

Can not fetch from database in React Native with Firebase?

I'm a newbie in React Native and struggling to fetch the data to Firebase database.
Basically, here's the flow of my data:
1. User chooses locations and their trip information ( name, startDate, endDate) --> stored in Redux
2. In the Redux store, at the time user creates the trip, I POST that trip to the Firebase database
3. After that, in the TripsListScreen, I fetch(method: 'GET') the trips from that database to show to the user
Here's the behavior, the TripsListScreen just keeps refreshing over and over, even though I successfully post the trips to the database. But the error is in the function which load the trips from the server ( so I think I couldn't fetch successfully from the server)
Error video
Here's the TripsListScreen
const TripsListScreen = props => {
const [isLoading, setIsLoading] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState();
const trips = useSelector(state => state.trips.trips); // The root reducer in App.js is trips
const dispatch = useDispatch();
const loadTrips = useCallback(async() => {
setError(null);
setIsRefreshing(true);
try {
await dispatch(tripActions.fetchTrip());
} catch (error) {
console.log(error)
setError(error);
}
setIsRefreshing(false);
},[dispatch, setIsLoading, setError]);
useEffect(() => {
const willFocus = props.navigation.addListener(
'willFocus',
loadTrips
);
return () => {willFocus.remove();}
},[loadTrips]);
useEffect(() => {
setIsLoading(true);
loadTrips().then(
setIsLoading(false),
);
}, [dispatch, loadTrips])
if(isLoading){
return(
<View>
<ActivityIndicator size='large' color={Colors.primary} />
</View>
)
}
if(!isLoading && trips.length === 0){
return(
<View style={styles.container}>
<Text>No trips created. Let make some!</Text>
</View>
)
}
if (error) {
return (
<View style={[styles.container, {justifyContent: 'center', alignItems: 'center'}]}>
<Text>An error occurred!</Text>
<Button
title="Try again"
onPress={loadTrips}
color={Colors.primary}
/>
</View>
);
}
return(
<Layout style={[styles.container, {justifyContent: 'center', alignItems: 'center'}]}>
<Layout style={styles.header}>
<Layout style={styles.titleContainer}>
<Text style={styles.title}>Let's pack for your trip</Text>
</Layout>
<Layout style={styles.subtitleContainer}>
<Text style={styles.subtitle}>And share it with your friends</Text>
</Layout>
</Layout>
<View style={styles.list}>
<FlatList
onRefresh={loadTrips}
refreshing={isRefreshing}
horizontal={true}
data={trips.reverse()}
keyExtractor={item => item.id}
renderItem={(itemData => {
return(
<TripItem
onSelect={() => props.navigation.navigate('PlanningProcess', {screen: 'MainMapScreen', params: {doNotAddPlace: true}})}
onEdit={() => props.navigation.navigate('PlanningProcess', {screen: 'TripDescription'})}
eventName={itemData.item.name}
startDate={itemData.item.startDate}
endDate={itemData.item.endDate}
/>
)
})}
/>
</View>
</Layout>
);
};
Here's the tripReducer
import { ADD_TRIP, SET_TRIP } from '../../actions/trip/trip';
import { Trip } from '../../../src/models/trip';
const initialState = {
trips: []
}
export default tripReducer = (state = initialState, action) => {
switch(action.type){
case ADD_TRIP:
const newTrip = new Trip(
action.tripData.id,
action.tripData.ownerId,
action.tripData.name,
action.tripData.startDate,
action.tripData.endDate,
action.locations
);
return {
...state,
trips: state.trips.concat(newTrip),
}
case SET_TRIP:
return{
trips: action.trips
}
default: return state;
}
}
Here's the tripActions
import { Trip } from "../../../src/models/trip";
export const ADD_TRIP = 'ADD_TRIP';
export const SET_TRIP = 'SET_TRIP';
export const addTrip = (name, startDate, endDate, locations) => {
return async (dispatch, getState) => {
const token = getState().auth.user.token;
const userId = getState().auth.user.uid;
const response = await fetch(
`https://...(keep secret for safety)/trips.json?auth=${token}`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
startDate,
endDate,
locations,
ownerId: userId,
})
});
const resData = await response.json();
console.log(resData);
dispatch({
type: ADD_TRIP,
tripData:{
id: resData.name,
ownerId: userId,
name,
startDate,
endDate,
locations
}
})
}
};
export const fetchTrip = () => {
return async (dispatch, getState) => {
const userId = getState().auth.user.uid;
try {
const response = await fetch(
'https://...(keep secret for safety)/trips.json'
);
if(!response.ok){
throw new Error('Something went wrong, please try again!')
};
const resData = await response.json();
console.log(resData);
const loadedTrips = [];
for(let key in resData){
loadedTrips.push(new Trip(
key,
resData[key].ownerId,
resData[key].name,
resData[key].startDate,
resData[key].endDate,
resData[key].locations
))
};
dispatch({
type: SET_TRIP,
trips: loadedTrips.filter(trip => trip.ownerId === userId)
})
} catch (error) {
throw error;
}
}
}
Redux store flow:
1. ADD_TRIP: post trip information to the server (firebase database)
2. SET_TRIP: fetch trip information from the server, which is posted by the ADD_TRIP action ( to display on the screen for the user)
Here's the database after it receives the data from ADD_TRIP:
Here's the rules for Firebase database:
EDIT 1:
I tried to use axios and the request failed with error code 401, meaning the request hasn't be authorized.
PLEASE HELP
After, adding authentication in the request and editing the resData. I get in done now.
The response.json() can't perform since it's not a function to be awaited ( I think so )
All I need is to assign resData to the response.data. No need to awaiting it
try {
const response = await axios.get(
`https://meetupapp-21180.firebaseio.com/trips.json?auth=${token}`,{
method: 'GET',
}
)
// if(!response.ok){
// throw new Error('Something went wrong, please try again!')
// };
const resData = response.data;

Categories

Resources