React Native Expo: AxiosError: Network Error - reactjs

I use axios for my assignment. Axios works fine with my Login and Signup but when it comes to posting a blog, it keeps giving me this error:
[AxiosError: Network Error]
I'm actually testing my app on my real Android device and using my real server with my IP adress. I try to see what cause the error, even test my server with Postman but it doesn't work.
Here is my code (please don't mind my Vietnamese words):
import { Image, StyleSheet, Text, View, Button, TextInput, Alert } from 'react-native';
import React, { useState } from 'react';
import * as ImagePicker from 'expo-image-picker';
import * as FileSystem from 'expo-file-system';
import axios from 'axios';
const PostBlog = () => {
const [img_source, setimg_source] = useState(null)
const [img_base64, setiimg_base64] = useState(null)
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [image, setImage] = useState(null);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.canceled) {
setimg_source(result.assets[0].uri);
let _uri = result.assets[0].uri;
let file_ext = _uri.substring(_uri.lastIndexOf('.') + 1);
FileSystem.readAsStringAsync(result.assets[0].uri, { encoding: 'base64' })
.then((res) => {
setiimg_base64("data:image/" + file_ext + ";base64," + res);
console.log(img_base64);
});
}
}
const handleCreatePost = async () => {
const data = new FormData();
data.append('title', title);
data.append('content', content);
data.append('image', img_base64);
axios.post('http://192.168.43.219:3000/posts', data)
.then(response => {
Alert.alert('Thành công', 'Bạn đã đăng bài thành công');
console.log(response);
})
.catch(error => {
console.log(error);
Alert.alert('Thất bại', 'Vui lòng thử lại sau');
})
}
return (
<View style={styles.container}>
<Image styles={styles.image} />
<TextInput placeholder='Tiêu đề' style={styles.input} onChangeText={setTitle} value={title}/>
<TextInput placeholder='Nội dung' style={styles.input} onChangeText={setContent} value={content}/>
<Button title="Chọn ảnh từ thư viện" onPress={pickImage} />
{img_source && <Image source={{ uri: img_source }} style={{ width: 100, height: 100 }} />}
<Button title="Đăng blog" onPress={handleCreatePost}/>
</View>
)
}
export default PostBlog;
const styles = StyleSheet.create({
image: {
width: 100,
height: 100
},
container: {
flex: 1,
padding: 10,
backgroundColor: '#fff'
},
input: {
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 4,
padding: 10,
marginBottom: 10
}
});
Any idea about this problem? Thanks for helping me

Related

Expo app keeps returning TypeError: undefined is not an object (evaluating 'function')

I am creating a mobile app that takes a picture and then returns the objects it detected. the way it works is that i have heroku running the ml model api. the weird thing about this error is that it happened after my code worked and sent an api request which then returned a json of what it detected. and when i ran it again it gave me [TypeError: undefined is not an object (evaluating '_expo.ImageManipulator.manipulateAsync')]. i looked at the value of image and asset to see if they are undefined and the console printed false. i even tried
console.log(typeof image==='undefined')
console.log(typeof asset==='undefined')
console.log(typeof image=='undefined')
console.log(typeof asset=='undefined')
just to make sure that the value of the variables aren't undefined. i then commented out the function to see what would happen and i got [TypeError: undefined is not an object (evaluating '_this.toServer')]. i then restarted the expo server and did everything i did above again but it keeps giving me [TypeError: undefined is not an object (evaluating '_expo.ImageManipulator.manipulateAsync')]. the code below is the code for the function that saves the image and makes a post request.
const takePicture = async () => {
if (cameraRef) {
try {
const data = await cameraRef.current.takePictureAsync();
console.log(data);
setImage(data.uri);
} catch (error) {
console.log(error);
}
}
};
uriToBase64 = async (uri) => {
let base64 = await FS.readAsStringAsync(uri, {
encoding: FS.EncodingType.Base64,
});
return base64;
};
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
console.log(image===undefined)
console.log(asset===undefined)
console.log(image==undefined)
console.log(asset===undefined)
let manipResult = await ImageManipulator.manipulateAsync(
asset,[{ resize: { width: 800, height: 800 } }],{ format: 'jpg' });
let assetResized = await MediaLibrary.createAssetAsync(manipResult);
await this.toServer({
type:"image",
base64: uriToBase64(assetResized),
uri: assetResized,
});
setImage(null);
console.log('saved successfully');
} catch (error) {
console.log(error);
}
}
};
also if i do:
if(!(image==undefined))
to make it so that if the image is undefined it won't do anything i get
LOG [Error: Argument of an incompatible class: class java.util.HashMap cannot be passed as an argument to parameter expecting class java.lang.String.]
WARN Possible Unhandled Promise Rejection (id: 0):
Error: Argument of an incompatible class: class java.util.HashMap cannot be passed as an argument to parameter expecting class java.lang.String.
promiseMethodWrapper#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:22934:45
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:114097:40
readAsStringAsync$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:118249:92
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24672:19
tryCallTwo#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30323:9
doResolve#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30487:25
Promise#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30346:14
callInvokeWithMethodAndArg#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24671:33
_invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24676:157
async#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24762:69
readAsStringAsync#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:118236:38
_callee3$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120465:69
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24672:19
tryCallTwo#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30323:9
doResolve#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30487:25
Promise#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30346:14
callInvokeWithMethodAndArg#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24671:33
_invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24676:157
async#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24762:69
_callee3#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120460:40
_callee5$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120529:36
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24654:19
tryCallOne#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30314:16
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30415:27
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31506:26
_callTimer#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31406:17
_callReactNativeMicrotasksPass#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31441:17
callReactNativeMicrotasks#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31648:44
__callReactNativeMicrotasks#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23414:46
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23193:45
__guard#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23397:15
flushedQueue#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23192:21
flushedQueue#[native code]
invokeCallbackAndReturnFlushedQueue#[native code]
here is the entire code:
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, Image } from 'react-native';
import Constants from 'expo-constants';
import { Camera, CameraType } from 'expo-camera';
import * as MediaLibrary from 'expo-media-library';
import { MaterialIcons } from '#expo/vector-icons';
import Button from './src/components/Button';
import axios from 'axios'
import { Buffer } from "buffer";
import * as FS from "expo-file-system";
import { ImageManipulator } from 'expo';
export default function App() {
const [hasCameraPermission, setHasCameraPermission] = useState(null);
const [image, setImage] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const [flash, setFlash] = useState(Camera.Constants.FlashMode.off);
const cameraRef = useRef(null);
useEffect(() => {
(async () => {
MediaLibrary.requestPermissionsAsync();
const cameraStatus = await Camera.requestCameraPermissionsAsync();
setHasCameraPermission(cameraStatus.status === 'granted');
})();
}, []);
const takePicture = async () => {
if (cameraRef) {
try {
const data = await cameraRef.current.takePictureAsync();
console.log(data);
setImage(data.uri);
} catch (error) {
console.log(error);
}
}
};
uriToBase64 = async (uri) => {
let base64 = await FS.readAsStringAsync(uri, {
encoding: FS.EncodingType.Base64,
});
return base64;
};
toServer = async (mediaFile) => {
url = "censored url so that trolls wont use it ";
let response = await FS.uploadAsync(url, mediaFile.uri, {
headers: {
"content-type": "image/jpeg",
},
httpMethod: "POST",
uploadType: FS.FileSystemUploadType.BINARY_CONTENT,
});
console.log(response);
};
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
console.log(typeof image==='undefined')
console.log(typeof asset==='undefined')
console.log(typeof image=='undefined')
console.log(typeof asset=='undefined')
await this.toServer({
type:"image",
base64: uriToBase64(asset),
uri: asset,
});
setImage(null);
console.log('saved successfully');
} catch (error) {
console.log(error);
}
}
};
if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
{!image ? (
<Camera
style={styles.camera}
type={type}
ref={cameraRef}
flashMode={flash}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 30,
}}
>
<Button
title=""
icon="retweet"
onPress={() => {
setType(
type === CameraType.back ? CameraType.front : CameraType.back
);
}}
/>
<Button
onPress={() =>
setFlash(
flash === Camera.Constants.FlashMode.off
? Camera.Constants.FlashMode.on
: Camera.Constants.FlashMode.off
)
}
icon="flash"
color={flash === Camera.Constants.FlashMode.off ? 'gray' : '#fff'}
/>
</View>
</Camera>
) : (
<Image source={{ uri: image }} style={styles.camera} />
)}
<View style={styles.controls}>
{image ? (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 50,
}}
>
<Button
title="Re-take"
onPress={() => setImage(null)}
icon="retweet"
/>
<Button title="Save" onPress={savePicture} icon="check" />
</View>
) : (
<Button title="Take a picture" onPress={takePicture} icon="camera" />
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#000',
padding: 8,
},
controls: {
flex: 0.5,
},
button: {
height: 40,
borderRadius: 6,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontWeight: 'bold',
fontSize: 16,
color: '#E9730F',
marginLeft: 10,
},
camera: {
flex: 5,
borderRadius: 20,
},
topControls: {
flex: 1,
},
});

REACT NATIVE: fetching array of image from firestore database collection to carousel

Good day.
I have managed to fetch an array of images from firestore database collection, the only problem is that it seems that I cannot loop over the array that I am retrieving from the database.
I need to dynamically display my images on the carousel.
import React, { useState, useEffect, useCallback } from 'react';
import { Text, Dimensions, StyleSheet, View, Image } from 'react-native';
import { SwiperFlatList } from 'react-native-swiper-flatlist';
import firestore from '#react-native-firebase/firestore';
import { white } from 'react-native-paper/lib/typescript/styles/colors';
import { color } from 'react-native-reanimated';
import Carousel from 'react-native-reanimated-carousel';
//const colors = ["tomato", "thistle", "skyblue", "teal"];
const names = [{"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FJB.png?alt=media&token=377f1629-6807-4343-b826-93d1c2bc5de6"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2Fgymtarp.png?alt=media&token=b2d1c923-2b5c-4066-bf8f-dc12de399059"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/photos%2Fb75d0848-b37f-4584-ab46-f355ca838e83.jpg?alt=media&token=adaa8559-de91-4ced-b056-84300123102e"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FSANDO.png?alt=media&token=274c946b-7f20-4c07-8545-431a0558257c"}];
const App = () => {
const [ads, setAds] = useState([]); // Initial empty array of ads
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
//.orderBy('Menu', 'asc')
.onSnapshot(querySnapshot => {
//const ads = [];
/*
querySnapshot.forEach(documentSnapshot => {
ads.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
*/
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
ads.push({
//id: doc.id,
AdImage,
//Price,
});
});
setAds(ads);
console.log(ads);
//console.log(Object.entries(ads));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
return (
<View style={styles.container}>
<SwiperFlatList
autoplay
autoplayDelay={2}
autoplayLoop
index={2}
showPagination
data={ads}
renderItem={({ item }) => (
<View style={[styles.child, { backgroundColor: item }]}>
<Text style={styles.text}>{item.AdImage}</Text>
<Image
style={{
width: "100%",
height: "30%",
position: 'absolute',
top:0,
alignItems: 'center',
justifyContent: 'center'}}
source={{uri : item.AdImage}}
resizeMode={'stretch'} // cover or contain its upto you view look
/>
</View>
)}
/>
</View>
)
};
const { width } = Dimensions.get('window');
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', },
child: { width, justifyContent: 'center', height: '100%' },
text: { fontSize: width * 0.1, textAlign: 'center' },
});
export default App;
Thank you for answering my question. Mabuhay! I'm from the Philippines.
The problem I am seeing is that probably meanwhile you are receiving asynchronously the snapshots, the setState did not ended running (a race condition between the velocity receiving snapshots and the exact time needed to persist the state)
I would try to delay the state change and use the previous state value in the setter, like this:
useEffect(() => {.
const subscriber = firestore()
.collection('AdsDB')
.onSnapshot(querySnapshot => {
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
setTimeout(() => {
setAds((prevAds) => [...prevAds, AdImage]);
}, 500);
});
console.log(ads);
//console.log(Object.entries(adsFromFirebase));
});
These are my code, Sir. It gives an empty array.
import React, { useState, useEffect, useCallback } from 'react';
import { Text, Dimensions, StyleSheet, View, Image } from 'react-native';
import { SwiperFlatList } from 'react-native-swiper-flatlist';
import firestore from '#react-native-firebase/firestore';
import { white } from 'react-native-paper/lib/typescript/styles/colors';
import { color } from 'react-native-reanimated';
const colors = ["tomato", "thistle", "skyblue", "teal"];
const names = [{"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FJB.png?alt=media&token=377f1629-6807-4343-b826-93d1c2bc5de6"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2Fgymtarp.png?alt=media&token=b2d1c923-2b5c-4066-bf8f-dc12de399059"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/photos%2Fb75d0848-b37f-4584-ab46-f355ca838e83.jpg?alt=media&token=adaa8559-de91-4ced-b056-84300123102e"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FSANDO.png?alt=media&token=274c946b-7f20-4c07-8545-431a0558257c"}];
const App = () => {
const [ads, setAds] = useState([]); // Initial empty array of ads
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
.onSnapshot(querySnapshot => {
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
setTimeout(() => {
setAds((prevAds) => [...prevAds, AdImage]);
}, 500);
});
console.log(ads);
//console.log(Object.entries(adsFromFirebase));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
/*
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
//.orderBy('Menu', 'asc')
.onSnapshot(querySnapshot => {
//const ads = [];
/*
querySnapshot.forEach(documentSnapshot => {
ads.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
ads.push({
//id: doc.id,
AdImage,
//Price,
});
});
setAds(ads);
//console.log(ads);
//console.log(Object.entries(ads));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
*/
return (
<View style={styles.container}>
<SwiperFlatList
autoplay
autoplayDelay={2}
autoplayLoop
index={2}
data={ads}
renderItem={({ item }) => (
<View style={[styles.child, { backgroundColor: item.colors }]}>
<Text style={styles.text}>{item.AdImage}</Text>
<Image
style={{
width: "100%",
height: "30%",
position: 'absolute',
top:0,
alignItems: 'center',
justifyContent: 'center'}}
source={{uri : item.AdImage}}
resizeMode={'stretch'} // cover or contain its upto you view look
/>
{/*}*/}
</View>
)}
/>
</View>
)
};
const { width } = Dimensions.get('window');
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', },
child: { width, justifyContent: 'center', height: '100%' },
text: { fontSize: width * 0.1, textAlign: 'center' },
});
export default App;
This is the output.
LOG Running "myApp" with {"rootTag":21}
LOG []

React Native: Error: Must provide `bucket` option with your AWS bucket name

I have a simple React Native application that utilizes an AWS bucket for photo storage. I currently have the AWS config coded in a file in which it is being used but I would like to move it to it's own file and then import it when needed.
This is what the config.js file looks like when abstracted from the other files:
const config = {
keyPrefix: 'Uploaded Photos/',
bucket: 'rn-mobile-app-bucket',
region: 'us-east-2',
accessKey: 'MYACCESSKEY',
secretKey: 'MYSECRETKEY',
successActionStatus: 201
}
This is the file that it is currently being used in:
import React, { useEffect, useState } from 'react';
import { Button, View, Text, TextInput, Picker } from 'react-native';
import { Header } from 'react-native-elements';
import { styles } from './styles.js';
import * as ImagePicker from 'expo-image-picker';
import { RNS3 } from 'react-native-aws3';
import Modal from 'react-native-modal';
const FormSubmit = ({navigation, route}) => {
const [Name, onChangeName] = useState(null);
const [Phone, onChangePhone] = useState(null);
const [Email, onChangeEmail] = useState(null);
const [selectedValue, setSelectedValue] = useState(null);
const [MileMarker, onChangeMileMarker] = useState(null);
const [Comments, onChangeComments] = useState(null);
const [RoadName, onChangeRoadName] = useState(null);
const [image, setImage] = useState(null);
const [hasPermission, setHasPermission] = useState(null);
const [isModalVisible, setModalVisible] = useState(false);
const counties = ["Barbour", "Berkeley", "Boone", "Braxton", "Brooke", "Cabell", "Calhoun", "Clay", "Doddridge", "Fayette", "Gilmer", "Grant", "Greenbrier", "Hampshire", "Hancock", "Hardy",
"Harrison", "Jackson", "Jefferson", "Kanawha", "Lewis", "Lincoln", "Logan", "Marion", "Marshall", "Mason", "Mercer", "Mineral", "Mingo", "Monongalia", "Monroe", "Morgan", "McDowell",
"Nicholas", "Ohio", "Pendleton", "Pleasants", "Pocahontas", "Preston", "Putnam", "Raleigh", "Randolph", "Ritchie", "Roane", "Summers", "Taylor", "Tucker", "Tyler", "Upshur", "Wayne",
"Webster", "Wetzel", "Wirt", "Wood", "Wyoming"]
//This needs to happen when I press the button I think but it doesnt really seem to work if I do.
useEffect(() => {
(async () => {
if (Platform.OS !== 'web') {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
}
const {status} = await ImagePicker.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImage(result.uri);
toggleModal();
}
};
const takeImage = async () => {
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImage(result.uri);
toggleModal();
}
};
//POST a new form to the database
const postForm = async () =>{
fetch('http://10.0.2.2:5000/forms', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
Name: Name,
Phone: Phone,
Email: Email,
County: selectedValue,
RoadName: RoadName,
MileMarker: MileMarker,
Comments: Comments,
Path: "https://rn-mobile-app-bucket.s3.us-east-2.amazonaws.com/Uploaded+Photos/" + Name + Date.now()
})
}).then(response =>{
if(response.ok){
return response.json();
}
}).then(data => console.log(data));
}
//Save image to AWS S3 bucket
const saveImage = async () => {
const file = {
uri: image,
name: Name + Phone, //This needs to be a better naming convention
type: 'image/png'
}
const config = {
keyPrefix: 'Uploaded Photos/',
bucket: 'rn-mobile-app-bucket',
region: 'us-east-2',
accessKey: 'MYACCESS',
secretKey: 'SECRETKEY',
successActionStatus: 201
}
RNS3.put(file, config).then((response) => {
console.log(response);
});
}
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
return (
<View style={styles.container}>
<Header
//leftComponent={{ icon: 'menu', color: '#fff' }}
centerComponent={{ text: 'Create request', style: { color: '#fff', fontSize: 25} }}
//rightComponent={{ icon: 'home', color: '#fff' }}
/>
<View style={styles.rowContainer}>
<TextInput
style={styles.input}
placeholder = "Name"
onChangeText={onChangeName}
value={Name}
/>
</View>
<View style={styles.rowContainer}>
<TextInput
style={styles.input}
placeholder = "Phone"
onChangeText={onChangePhone}
value={Phone}
/>
</View>
<View style={styles.rowContainer}>
<TextInput
style={styles.input}
placeholder = "Email"
onChangeText={onChangeEmail}
value={Email}
/>
</View>
<View style={styles.rowContainer}>
<Picker
style={styles.charPicker}
mode="dropdown"
selectedValue={selectedValue}
onValueChange={(itemValue, itemIndex) => setSelectedValue(itemValue)}
>
{counties.map((item, index) => {
return (<Picker.Item label={item} value={item} key={index}/>)
})}
</Picker>
</View>
<View style={styles.rowContainer}>
<TextInput
style={styles.input}
placeholder = "Mile Marker"
onChangeText={onChangeMileMarker}
value={MileMarker}
/>
</View>
<View style={styles.rowContainer}>
<TextInput
style={styles.input}
placeholder = "Road Name"
onChangeText={onChangeRoadName}
value={RoadName}
/>
</View>
<View style={styles.rowContainer}>
<TextInput
style={styles.textArea}
placeholder = "Describe the problem..."
numberOfLines={10}
multiline={true}
onChangeText={onChangeComments}
value={Comments}
/>
</View>
<Button title="Upload Photo" onPress={toggleModal} />
<Button
style = {styles.button}
title="Submit"
onPress={() => {
saveImage();
postForm();
navigation.navigate('ThankYou');
}}
color="#19AC52"
/>
<Modal isVisible={isModalVisible}>
<View style={{flex: 1}}>
<Text>Hello!</Text>
<Button title="Camera Roll" onPress={pickImage} />
<Button title="Camera" onPress={takeImage} />
<Button title="Cancel" onPress={toggleModal} />
</View>
</Modal>
</View>
);
}
export default FormSubmit;
In which the section in question is this part:
//Save image to AWS S3 bucket
const saveImage = async () => {
const file = {
uri: image,
name: Name + Phone, //This needs to be a better naming convention
type: 'image/png'
}
const config = {
keyPrefix: 'Uploaded Photos/',
bucket: 'rn-mobile-app-bucket',
region: 'us-east-2',
accessKey: 'ACCESSKEY',
secretKey: 'SECRETKEY',
successActionStatus: 201
}
RNS3.put(file, config).then((response) => {
console.log(response);
});
}
If I comment out the config struct and try to import it like this:
import * as config from '../../config';
or this
import config from '../../config';
I get the error
[Unhandled promise rejection: Error: Must provide `bucket` option with your AWS bucket name]
What am I doing wrong and how can I properly import the config struct?
In your config.js try changing it to export const config =
And then when importing it change it to import {config} from ../../config
and pass that config object straight into the s3.put call
A handy cheatsheet to use for imports/exports is : https://medium.com/dailyjs/javascript-module-cheatsheet-7bd474f1d829

How to aggregate values from a list and display in react native app?

I have a list which I get from firebase and displaying those values in the UI using SwipeListView.
The list data contains details like: coin price, count of coins purchased, total cost of the coins as price,count and amount. And some other fields.
Now, I want to make aggregate of all the coins and display in the text field. But the aggregation I am not able to set.
I tried creating two variables and setting those using hooks but getting error as
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
Can you please suggest the approach please. Below is my code.
import React, { useEffect, useState } from "react";
import {
FlatList,
Keyboard,
Text,
TextInput,
TouchableOpacity,
View,
StyleSheet,
} from "react-native";
import { Avatar, Button, Card, Title, Paragraph } from "react-native-paper";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";
import { Icon } from "react-native-elements";
export default function OrderList(props) {
const LeftContent = (props) => <Avatar.Icon {...props} icon="folder" />;
const [orderText, setOrderText] = useState("");
const [orders, setOrders] = useState([]);
const orderRef = firebase.firestore().collection("orders");
const userID = props.route.params.userID;
const coin = props.route.params.coin;
let totalCost = 0;
let totalCount = 0;
const [totalCost, setTotalCost] = useState[""];
const [totalCount, setTotalCount] = useState[""];
const [averageValue, setAverageValue] = useState("");
//averageValue = (totalCost / totalCount).toString();
useEffect(() => {
orderRef
.where("authorID", "==", userID)
.where("name", "==", coin)
.orderBy("createdAt")
.onSnapshot(
(querySnapshot) => {
const newOrders = [];
querySnapshot.forEach((doc) => {
const order = doc.data();
order.id = doc.id;
newOrders.push(order);
});
setOrders(newOrders);
},
(error) => {
console.log(error);
}
);
}, []);
useEffect(() => {
setAverageValue(
(parseFloat(totalCost) / parseFloat(totalCount)).toString()
);
}, [totalCount, totalCost]);
const onAddButtonPress = () => {
props.navigation.navigate("CreateOrder", {
coin: coin,
userID: userID,
orderRef,
});
};
const renderOrder = ({ item, index }) => {
console.log("----------------------");
console.log(item.createdAt.toDate().toString());
console.log("----------------------");
setTotalCost(parseFloat(totalCost) + parseFloat(item.price));
setTotalCount(parseFloat(totalCount) + parseFloat(item.count));
console.log(totalCost);
console.log(totalCount);
return (
<View style={styles1.rowFront}>
<Text>
{index}. {item.price} {item.amount} {item.count}
{"\n" + item.createdAt.toDate().toString()}
</Text>
<Icon name={"flight-takeoff"} />
</View>
);
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
<Text style={styles.buttonText}>Click here to create new order..</Text>
</TouchableOpacity>
<Text>Average: {averageValue}</Text>
{orders && (
<SwipeListView
data={orders}
keyExtractor={(item) => item.id}
renderItem={renderOrder}
removeClippedSubviews={true}
/>
)}
</View>
);
}
const styles1 = StyleSheet.create({
rowFront: {
alignItems: "center",
backgroundColor: "#FFF",
borderBottomWidth: 0.25,
justifyContent: "center",
height: 50,
},
rowBack: {
alignItems: "center",
backgroundColor: "#DDD",
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
paddingLeft: 15,
},
backRightBtn: {
alignItems: "center",
bottom: 0,
justifyContent: "center",
position: "absolute",
top: 0,
width: 75,
backgroundColor: "red",
right: 0,
},
});
Modified code with normal variables and useEffect linked to them to change average.
import React, { useEffect, useState } from "react";
import {
FlatList,
Keyboard,
Text,
TextInput,
TouchableOpacity,
View,
StyleSheet,
} from "react-native";
import { Avatar, Button, Card, Title, Paragraph } from "react-native-paper";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";
import { Icon } from "react-native-elements";
export default function OrderList(props) {
const LeftContent = (props) => <Avatar.Icon {...props} icon="folder" />;
const [orderText, setOrderText] = useState("");
const [orders, setOrders] = useState([]);
const orderRef = firebase.firestore().collection("orders");
const userID = props.route.params.userID;
const coin = props.route.params.coin;
let totalCost = 0;
let totalCount = 0;
//const [totalCost, setTotalCost] = useState[""];
//const [totalCount, setTotalCount] = useState[""];
const [averageValue, setAverageValue] = useState("");
//averageValue = (totalCost / totalCount).toString();
useEffect(() => {
orderRef
.where("authorID", "==", userID)
.where("name", "==", coin)
.orderBy("createdAt")
.onSnapshot(
(querySnapshot) => {
const newOrders = [];
querySnapshot.forEach((doc) => {
const order = doc.data();
order.id = doc.id;
newOrders.push(order);
});
setOrders(newOrders);
},
(error) => {
console.log(error);
}
);
}, []);
useEffect(() => {
setAverageValue(
(parseFloat(totalCost) / parseFloat(totalCount)).toString()
);
}, [totalCount, totalCost]);
const onAddButtonPress = () => {
props.navigation.navigate("CreateOrder", {
coin: coin,
userID: userID,
orderRef,
});
};
const renderOrder = ({ item, index }) => {
console.log("----------------------");
console.log(item.createdAt.toDate().toString());
console.log("----------------------");
//setTotalCost(parseFloat(totalCost) + parseFloat(item.price));
//setTotalCount(parseFloat(totalCount) + parseFloat(item.count));
totalCost = parseFloat(totalCost) + parseFloat(item.price);
totalCount = parseFloat(totalCount) + parseFloat(item.count);
console.log(totalCost);
console.log(totalCount);
return (
<View style={styles1.rowFront}>
<Text>
{index}. {item.price} {item.amount} {item.count}
{"\n" + item.createdAt.toDate().toString()}
</Text>
<Icon name={"flight-takeoff"} />
</View>
);
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
<Text style={styles.buttonText}>Click here to create new order..</Text>
</TouchableOpacity>
<Text>Average: {averageValue}</Text>
{orders && (
<SwipeListView
data={orders}
keyExtractor={(item) => item.id}
renderItem={renderOrder}
removeClippedSubviews={true}
/>
)}
</View>
);
}
const styles1 = StyleSheet.create({
rowFront: {
alignItems: "center",
backgroundColor: "#FFF",
borderBottomWidth: 0.25,
justifyContent: "center",
height: 50,
},
rowBack: {
alignItems: "center",
backgroundColor: "#DDD",
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
paddingLeft: 15,
},
backRightBtn: {
alignItems: "center",
bottom: 0,
justifyContent: "center",
position: "absolute",
top: 0,
width: 75,
backgroundColor: "red",
right: 0,
},
});
.
thanks #jnpdx it is working now. Based on your inputs, my changes.
import React, { useEffect, useState } from "react";
import {
FlatList,
Keyboard,
Text,
TextInput,
TouchableOpacity,
View,
StyleSheet,
} from "react-native";
import { Avatar, Button, Card, Title, Paragraph } from "react-native-paper";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";
import { Icon } from "react-native-elements";
import { createIconSetFromFontello } from "#expo/vector-icons";
export default function OrderList(props) {
const LeftContent = (props) => <Avatar.Icon {...props} icon="folder" />;
const [orderText, setOrderText] = useState("");
const [orders, setOrders] = useState([]);
const orderRef = firebase.firestore().collection("orders");
const userID = props.route.params.userID;
const coin = props.route.params.coin;
//averageValue = (totalCost / totalCount).toString();
const [averageValue, setAverageValue] = useState("");
useEffect(() => {
orderRef
.where("authorID", "==", userID)
.where("name", "==", coin)
.orderBy("createdAt")
.onSnapshot(
(querySnapshot) => {
const newOrders = [];
querySnapshot.forEach((doc) => {
const order = doc.data();
order.id = doc.id;
newOrders.push(order);
});
setOrders(newOrders);
},
(error) => {
console.log(error);
}
);
}, []);
useEffect(() => {
//calculate and set anything like totalCost, averageValue, etc here
console.log("---came to orders effect---");
//console.log(orders);
let totalCost = 0;
let totalCount = 0;
orders.forEach((item, index) => {
console.log(item);
console.log(index);
totalCost += parseFloat(item.amount);
totalCount += parseFloat(item.count);
});
setAverageValue((totalCost / totalCount).toString());
}, [orders]);
/*
useEffect(() => {
let avg = (parseFloat(totalCost) / parseFloat(totalCount)).toString();
console.log("Avg:" + avg);
setAverageValue(avg);
}, [totalCount, totalCost]);
*/
const onAddButtonPress = () => {
props.navigation.navigate("CreateOrder", {
coin: coin,
userID: userID,
orderRef,
});
};
const renderOrder = ({ item, index }) => {
//console.log("----------------------");
//console.log(item.createdAt.toDate().toString());
//console.log("----------------------");
//setTotalCost(parseFloat(totalCost) + parseFloat(item.price));
//setTotalCount(parseFloat(totalCount) + parseFloat(item.count));
//totalCost = parseFloat(totalCost) + parseFloat(item.price);
//totalCount = parseFloat(totalCount) + parseFloat(item.count);
//console.log(totalCost);
//console.log(totalCount);
return (
<View style={styles1.rowFront}>
<Text>
{index}. {item.price} {item.amount} {item.count}
{"\n" + item.createdAt.toDate().toString()}
</Text>
<Icon name={"flight-takeoff"} />
</View>
);
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
<Text style={styles.buttonText}>Click here to create new order..</Text>
</TouchableOpacity>
{orders.length === 0 && (
<Text>Please order some coins in currency: {coin}</Text>
)}
{orders && orders.length > 0 && (
<>
<Text>Average Value: {averageValue}</Text>
<SwipeListView
data={orders}
keyExtractor={(item) => item.id}
renderItem={renderOrder}
removeClippedSubviews={true}
/>
</>
)}
</View>
);
}
const styles1 = StyleSheet.create({
rowFront: {
alignItems: "center",
backgroundColor: "#FFF",
borderBottomWidth: 0.25,
justifyContent: "center",
height: 50,
},
rowBack: {
alignItems: "center",
backgroundColor: "#DDD",
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
paddingLeft: 15,
},
backRightBtn: {
alignItems: "center",
bottom: 0,
justifyContent: "center",
position: "absolute",
top: 0,
width: 75,
backgroundColor: "red",
right: 0,
},
});
You're calling useState hook functions (setTotalCost and setTotalCount) inside your render function. This will end up causing issues like the error that you're seeing or even worse, an infinite loop.
Instead of calling these when rendering, use useEffect instead and perform the necessarily calculations whenever the related dependencies change. It looks like you're already doing that for setAverageValue, so you're familiar with what's involved in doing that.
Update, based on comments:
useEffect(() => {
//calculate and set anything like totalCost, averageValue, etc here
}, [orders])

How to re render component without changing state

I have a component that fetch data first. then I manipulate the data but it doesn't change value until I change the screen and return back. Here I change the data based on the categories and doctors which i fetch using redux. but transformed data remains empty until i back to the page for the second time. Thanks for your help
import React, { useState, useEffect, useCallback } from "react";
import {
View,
Text,
StyleSheet,
ActivityIndicator,
FlatList,
Dimensions,
} from "react-native";
import { useSelector, useDispatch } from "react-redux";
import Colors from "../../constants/Colors";
import * as DoctorsActions from "../../store/actions/Doctors";
const { height } = Dimensions.get("window");
const ConcultationMainScreen = (props) => {
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");
const categories = useSelector((state) => state.categories.categories);
const doctors = useSelector((state) => state.doctors.doctors);
const loadAllDoctors = useCallback(async () => {
try {
await dispatch(DoctorsActions.getDoctors());
} catch (err) {
setError(err);
console.log(error);
}
}, [dispatch, setError]);
useEffect(() => {
setIsLoading(true);
loadAllDoctors().then(() => {
setIsLoading(false);
});
}, [dispatch, loadAllDoctors]);
if (isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" color={Colors.blue} />
</View>
);
}
let transformedData = [];
for (const cat in categories) {
let doctorsOfCategory = [];
for (const doc in doctors) {
if (doctors[doc].categories[0] === categories[cat].name) {
doctorsOfCategory.push({
doctorName: doctors[doc].name,
});
} else {
continue;
}
}
transformedData.push({
categoryName: categories[cat].name,
doctorsOfCategory: doctorsOfCategory,
});
}
console.log(transformedData);
const renderConsultCategories = (ItemData) => {
return (
<View style={styles.item}>
<View style={styles.titleContainer}>
<Text>
گفتگو و مشاوره با متخصصین <Text>{ItemData.item.categoryName}</Text>
</Text>
</View>
</View>
);
};
return (
<View style={styles.screen}>
<FlatList
data={transformedData}
keyExtractor={(item) => item.categoryName}
renderItem={renderConsultCategories}
/>
</View>
);
};
export const screenOptions = (navData) => {
return {
headerTitle: "صفحه مشاوره",
headerTitleAlign: "center",
};
};
const styles = StyleSheet.create({
screen: {
flex: 1,
},
centered: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
item: {
flexDirection: "row-reverse",
width: "100%",
height: height / 8,
marginVertical: 10,
borderBottomWidth: 1,
},
});
export default ConcultationMainScreen;
Use this.forceUpdate() to re-render without calling setState().

Resources