React-Native variable from API call is throwing an error - reactjs

I’m really rusty with my react-native, haven’t touched it in like 4 years.
I am trying to extract a cryptocurrency price from a publicly available API (as shown in the code below). i think I got the price but packing that value into something that’s usable is proving to be difficult. What am i doing wrong ? Either I haven’t set up the const correctly or something else is going on.
import React, {Component, useState, useEffect} from 'react';
import {AppRegistry, StyleSheet, Text, View} from 'react-native';
const getPriceFromApi = () => {
//GET request
fetch('https://api.coingecko.com/api/v3/simple/price?ids=bone-shibaswap&vs_currencies=usd', {
method: 'GET',
})
.then((response) => response.json())
//If response is json then in success
.then((responseJson) => {
//Success
return responseJson;
})
}
const App = () => {
const [price, setPrice] = useState([]);
useEffect(() => {
const fetchPrice = async () => {
const data = await getPriceFromApi();
setPrice(data);
// this should produce ONE value and one value only.
// however it’s throwing an error, grrrrr.
}
}, [getPriceFromApi])
return ();
type Props = {};
export default class MyApp extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.bone}>
🍖
</Text>
<Text style={styles.welcome}>
you have > 120.00
</Text>
<Text style={styles.instructions}>
the value of bone is:
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#2A2734',
},
bone: {
fontSize: 64,
textAlign: 'center',
margin: 10,
color: 'red'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color: 'white'
},
instructions: {
textAlign: 'center',
color: '#B0B0B0',
marginBottom: 5,
},
});
// You must register the main component
// with the same name as the project
AppRegistry.registerComponent(
'bone-price', () => MyApp
);

If you are writing a another function for fetching data from API, you may forget to return the value by fetch. It will always return undefined.
You should modify the function getPriceFromApi().
const getPriceFromApi = () => {
//This return is for function - getPriceFromApi()
return fetch('https://api.coingecko.com/api/v3/simple/price?ids=bone-shibaswap&vs_currencies=usd', {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
//This return is for function - fetch()
return responseJson;
})
}

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 []

useSelector returns an undefined, but I'm not able to access to the value

I'm programming this simple app in react native, but when I try to make the axios request I'm not able to concatenate the url and the "user" and "repo" const taken from the store.
console.log(apiurl) gives me "https://api.github.com/repos/undefined/undefined"
but if I type console.log(user) it gives me the actual value of user const.
How can I access create the axios request using user and repo const?
import {
View,
Text,
StyleSheet
} from 'react-native';
import { useSelector, useDispatch} from 'react-redux';
import { NavigationContainer, useNavigation } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import axios from 'axios';
import setResponse from '../actions';
import NetInfo from "#react-native-community/netinfo";
export default function homeScreen() {
const apiurl = 'https://api.github.com/repos/' + user + '/' + repo;
const user = useSelector(state => state.user);
const repo = useSelector(state => state.repo);
const response = useSelector(state => state.response)
const navigation = useNavigation();
const dispatch = useDispatch();
const [state, setState] = useState({
color: "",
isConnected: true,
});
const check = () => {
console.log(user);
console.log(repo);
console.log(apiurl);
axios.get('https://api.github.com/repos/'+ user+ '/' + repo).then(res => {
console.log(res.data.name);
dispatch(setResponse(res.data.message));
}).catch(error => console.log(error));
if (response === "Not Found") {
setState(prevState => {
return { ...prevState, color: "#ffacac" };
});
}
else if (state.isConnected == false) {
dispatch(setResponse("disconnected"));
setState(prevState => {
return { ...prevState, color: "#ffacac" };
});
}
else if (response == null) {
setState(prevState => {
return { ...prevState, color: "#caffda" };
});
}
}
return (
<View style={{flex: 1, backgroundColor: state.color}}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Set the repository address</Text>
</View>
<View style={styles.githubLink}>
<Text style={styles.link1}>github.com</Text>
<View style={styles.inputContainer}>
<Text style={styles.link1}>/</Text>
<Text style={styles.link2} onPress={() => navigation.navigate('User')} >{user}</Text>
</View>
<View style={styles.inputContainer}>
<Text style={styles.link1}>/</Text>
<Text style={styles.link2} onPress={() => navigation.navigate('Repo')} >{repo}</Text>
</View>
</View>
<View style={styles.buttonContainer}>
<Text style={styles.button} onPress={check}>CHECK</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
titleContainer: {
flex: 1.5,
justifyContent: "center",
paddingLeft: 12,
},
title: {
fontSize: 28,
fontFamily: "OpenSans-SemiBold",
},
githubLink: {
flex: 3,
paddingLeft: 12,
justifyContent: "center",
},
inputContainer: {
flexDirection: "row",
},
link1: {
fontSize: 38,
fontFamily: "OpenSans-Regular",
},
link2: {
fontSize: 38,
fontFamily: "OpenSans-Regular",
color: "grey"
},
buttonContainer: {
flex: 5.5,
justifyContent: "flex-end",
alignItems: "flex-end",
padding: 8,
},
button: {
fontSize: 25,
fontFamily: "OpenSans-Bold",
}
});
First, you need to make sure that the selector data from the state is not empty. Before actually doing the request you can check if the values are empty/undefined.
I also would advise you to more structure the way you are doing requests now. The Redux Toolkit has some nice examples for structuring your code to make it more maintainable. See their site

React - Value from API doesn't appear in View

I'm very new to React Native and following a course where I meet this issue :
This component shows "TEXT" but doesn't show {film.title}
_displayFilm() {
const { film } = this.state
if (film != undefined) {
return (
<ScrollView style={styles.scrollview_container}>
<Text>TEXT</Text>
<Text>{film.title}</Text>
</ScrollView>
)
}
}
I'm Using Atom in Ubuntu and use Expo Android App to see the result.
Another inconvenient I have is that I don't get logs from console.log() in Atom terminal that could have helped me for example to see complete json film object.
The value "title is correct (use in another page of my app).
If anybody have an idea how to solve it, thanks a lot !
If useful, here is the complete file content :
// Components/FilmDetail.js
import React from 'react'
import { StyleSheet, View, Text, ActivityIndicator, ScrollView, Image } from 'react-native'
import { getFilmDetailFromApi, getImageFromApi } from '../API/TMDBApi'
import moment from 'moment'
import numeral from 'numeral'
class FilmDetail extends React.Component {
constructor(props) {
super(props)
this.state = {
film: undefined,
isLoading: true
}
}
componentDidMount() {
getFilmDetailFromApi(this.props.navigation.state.params.idFilm).then(data => {
this.setState({
film: data,
isLoading: false
})
})
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
</View>
)
}
}
_displayFilm() {
const { film } = this.state
if (film != undefined) {
return (
<ScrollView style={styles.scrollview_container}>
<Text>TEXT</Text>
<Text>{film.title}</Text>
<Text style={styles.title_text}>{film.release_date}</Text>
<Text style={styles.title_text}>{film.backdrop_path}</Text>
</ScrollView>
)
}
}
render() {
return (
<View style={styles.main_container}>
{this._displayLoading()}
{this._displayFilm()}
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1
},
loading_container: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
scrollview_container: {
flex: 1
},
image: {
height: 169,
margin: 5
},
title_text: {
fontWeight: 'bold',
fontSize: 35,
flex: 1,
flexWrap: 'wrap',
marginLeft: 5,
marginRight: 5,
marginTop: 10,
marginBottom: 10,
color: '#000000',
textAlign: 'center'
},
description_text: {
fontStyle: 'italic',
color: '#666666',
margin: 5,
marginBottom: 15
},
default_text: {
marginLeft: 5,
marginRight: 5,
marginTop: 5,
}
})
export default FilmDetail
And the called API is here :
const API_TOKEN = "MY_API_TOKEN"
export function getFilmsFromApiWithSearchedText (text, page) {
const url = 'https://api.themoviedb.org/3/search/movie?api_key=' + API_TOKEN + '&language=fr&query=' + text + "&page=" + page
return fetch(url)
.then((response) => response.json())
.catch((error) => console.error(error))
}
export function getImageFromApi(name) {
return 'https://image.tmdb.org/t/p/w185' + name
}
export function getFilmDetailFromApi(id) {
const url = 'https://api.themoviedb.org/3/movie/' + id + 'api_key=' + API_TOKEN + '&language=fr'
return fetch(url)
.then((response) => response.json())
.catch((error) => console.log(error))
}
I think you are missing a ? in before the api_key:
const url = 'https://api.themoviedb.org/3/movie/' + id + '?api_key=' + API_TOKEN + '&language=fr'
you need to fix the console, as it must be showing that the response is wrong in the console atm... HTH
I believe your apiFunction should be more like this:
export function getFilmDetailFromApi(id) {
const url = 'https://api.themoviedb.org/3/movie/' + id + '?api_key=' + API_TOKEN + '&language=fr'
return fetch(url)
.then((response) => response.json())
.then((responseJson) => {
return responseJson;
})
.catch((error) => console.log(error))
}
Try this in your component:
this.state = {
film: {}, //change the undefined
isLoading: true
}
componentDidMount() {
this.getMovie();
}
getMovie() {
const movie = getFilmDetailFromApi(this.props.navigation.state.params.idFilm);
if (movie.hasOwnProperty('id')) { //that means a movie was returned
this.setState({ film: movie, isLoading: false });
}
}
The text in _displayFilm is showing because you have already set film as undefined. So as long as the state doesn't change, the text will show.
Change your _displayFilm:
_displayFilm() {
const { film } = this.state
if (film.hasOwnProperty('id')) {
return (
<ScrollView style={styles.scrollview_container}>
<Text>TEXT</Text>
<Text>{film.title}</Text>
<Text style={styles.title_text}>{film.release_date}</Text>
<Text style={styles.title_text}>{film.backdrop_path}</Text>
</ScrollView>
)
}
}
Now the problem might be that you are not getting the right data. It is possible that your data is contained in response.data.data or response.data and not just in response. So by all means console.log(response) and inspect

Getting "undefined" value for a variable outisde a fetch response in react native ?? Please?

/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {
Component,
} from 'react';
import {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} from 'react-native';
var REQUEST_URL = 'https://api.themoviedb.org/3/movie/popular?api_key=a667a62ffce29c5d1c5211e316ae43f6';
var REQUEST_URL_BASE_IMG = 'https://image.tmdb.org/t/p/w154/'
class Movies extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
var cast = "";
}
componentDidMount() {
this.fetchData(); //1st collection pulled
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.results),
loaded: true,
});
})
.done();
}
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
// fetchData2(movie){
// fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
// .then((response) => response.json())
// .then((responseJson) => {
// cast: responseJson.cast;
// })
// .catch((error) => {
// console.error(error);
// });
// }
renderMovie(movie,arr) {
var arr = [];
// I want the cast variable to be displayed on the screen. It is coming either undefined or prints "s1" which indicates no data.
fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
.then((response) => response.json())
.then((responseJson) => {
//cast: responseJson.cast;
//test = displaycast(responseJson.cast[0].name);
var cast = responseJson.cast[0].name;
console.log(cast);
})
.catch((error) => {
console.error(error);
});
// fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
// .then((response) => response.json())
// .then((responseJson) => {
// this.setState({
// cast: responseJson.cast,
// });
// })
// .catch((error) => {
// console.error(error);
// });
return (
<View style={styles.container}>
<Image
source={{uri: 'https://image.tmdb.org/t/p/w92/'+ movie.poster_path.replace(/\//g,"")}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{cast}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('Movies', () => Movies);
This is my code. My main concern is that I am getting the response from fetchData inside the renderMovie perfectly and storing it in cast variable. But if I try to access cast variable outside fetch. It shows undefined or empty string.
The entire point of not having this fetch with earlier is because I want to use the fetch response of 1st fetch Operation to get move.id and use it in the 2nd fetch request to get more details.
That's happening because JavaScript is asynchronous. I'd recommend doing something like your other fetch and set a loading state to know when you've fetched the cast and use that to render.

Resources