How to display data in flatlist from API - React Native - react-native

Im following this tutorial tutorial link
I'm attempting to fetch data from rapidAPI (using axios) and the JSON object array looks far more complex than than whats in the tutorial url
I cannot get the data to render in a flatlist
The code im using is below (coverted from turorial to my rapidApi axios request)
import React, { useEffect, useState } from "react";
import { FlatList, Text, View } from "react-native";
import axios from "axios";
function NotificationScreen() {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
console.log(data);
const options = {
method: "GET",
url: "https://api-football-v1.p.rapidapi.com/v3/fixtures",
params: {
league: "39",
season: "2022",
from: "2023-02-04",
to: "2023-02-05",
},
headers: {
"X-RapidAPI-Key": "mykey",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
},
};
useEffect(() => {
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
})
.finally(() => setLoading(false));
}, []);
return (
<View style={{ flex: 1, padding: 24, backgroundColor: "purple" }}>
{isLoading ? (
<Text>Loading...</Text>
) : (
<View
style={{
flex: 1,
flexDirection: "column",
justifyContent: "space-between",
}}
>
<Text style={{ fontSize: 20, color: "white", textAlign: "center" }}>
Fetch content using Axios
</Text>
<Text style={{ fontSize: 18, color: "white", textAlign: "center" }}>
{data.title}
</Text>
<Text
style={{
fontSize: 14,
color: "white",
textAlign: "center",
paddingBottom: 10,
}}
>
Articles:
</Text>
<FlatList
data={data.fixture}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Text style={{ color: "white" }}>{item.id}</Text>
)}
/>
</View>
)}
</View>
);
}
export default NotificationScreen;
I think it is because the data returned are as objects (going by the console log below) and it possibly need to do something more complex to render the data in lets say the "fixture" array. The flatlist doesnt display if use the above code
The below console log shows the data is being successfully pulled but its the rendering i'm lost with. It works with the simple json in the tutorial
console log
Disclaimer - I'm new to coding and react native in general so some of my terminology may be off

From the data that has been returned from the API you just need to access the fixture attribute from the response as code below:
const [data, setData] = useState(null);
useEffect(()=>{
getData()
},[])
const getData=async()=>{
await axios
.request(options)
.then(function (response) {
// distruct the data object
const {data} = response;
setData(data.response.fixture)
})
.catch(function (error) {
console.error(error);
})
.finally(() => setLoading(false));
}

Related

React Native reload flatlist each time user hits the API

React, {useCallback, useState, useEffect, useRef} from 'react';
import {
View,
SafeAreaView,
FlatList,
Image,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
} from 'react-native';
import Nodata from '../main/banking/common/Nodata';
import Icon from 'react-native-vector-icons/Ionicons';
import Toast from 'react-native-simple-toast';
import axios from 'axios';
import useSessionToken from '../hooks/useSessionToken';
import moment from 'moment';
import ListData from '../main/banking/common/ListData';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import ShimmerPlaceholder from 'react-native-shimmer-placeholder';
import LinearGradient from 'react-native-linear-gradient';
function CustomerNotes(props) {
const session = useSessionToken();
const textInputRef = useRef();
const [notes, setNotes] = useState('');
const [data, setData] = useState({
notesList: [],
visible: false,
});
useEffect(() => {
getNotes();
}, [session,data]);
const getNotes = async () => {
try {
const qs = require('qs');
let params = qs.stringify({
cust_id: props.customerId,
operation: 'notes_list',
});
await axios
.post(
'https://abc.cdhgfhg.com/adghagsa',
params,
{
headers: {
Cookie: session?.token,
'Content-Type': 'application/x-www-form-urlencoded',
},
},
)
.then(function (response) {
if (response.data.status === 1) {
console.log('customernotes', response.data.data.hits.hits);
setData({
...data,
notesList: response.data.data.hits.hits,
visible: false,
});
}
})
.catch(function (error) {
console.log('CustomerNoteserror', error);
});
} catch (error) {
console.log('CustomerNoteserror', error);
}
};
const renderItem = ({item, index}) => {
var initialtv = Number(index + 1).toString();
var formattedDate = moment(item._source.added_on).format(
'ddd, MMM DD YYYY',
);
// console.log('initial', item, initialtv);
const data = {
text: item._source.notes,
mobile: formattedDate,
amount: '',
};
return <ListData item={data} />;
};
const handleInputSubmit = useCallback(ev => {
const input = ev.nativeEvent.text;
// validate all you want here
setNotes(input);
}, []);
const submitNotes = () => {
if (notes.length > 0) {
setData(prevState => ({
...prevState,
visible: true,
}));
addNotes();
} else {
Toast.show('Enter Notes');
}
};
const addNotes = async () => {
try {
const qs = require('qs');
let params = qs.stringify({
cust_id: props.customerId,
operation: 'add_notes',
notes: notes,
});
await axios
.post(
'https://abc.cdhgfhg.com/adghagsa',
params,
{
headers: {
Cookie: session?.token,
'Content-Type': 'application/x-www-form-urlencoded',
},
},
)
.then(function (response) {
if (response.data.status === 1) {
// console.log('addNotes', response.data);
getNotes();
}
})
.catch(function (error) {
console.log('addNoteserror', error);
});
} catch (error) {
console.log('CustomerNoteserror', error);
}
};
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
{data.visible == true ? (
<ActivityIndicator
size="large"
color="#0096FF"
style={{
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
}}
/>
) : null}
{data.notesList.length != 0 ? (
<FlatList
data={data.notesList}
renderItem={renderItem}
style={{marginTop: hp('1.5%')}}
/>
) : (
<Nodata />
)}
<View
style={{
flex: 1,
flexDirection: 'row',
position: 'absolute',
bottom: 0,
marginBottom: '4%',
}}>
<TextInput
ref={textInputRef}
autoFocus={false}
style={styles.TextInputStyleClass}
placeholder="Write something"
placeholderTextColor={'#D0D0D0'}
onChangeText={
text => setNotes(text)
// (data.notes = text)
}
/>
<TouchableOpacity
onPress={() => submitNotes()}
style={{
height: 44,
width: 46,
backgroundColor: '#0096FF',
borderRadius: 6,
justifyContent: 'center',
alignItems: 'center',
elevation: 5,
marginRight: '4%',
}}>
<Icon
name={'send'}
size={20}
color="#ffffff"
style={{alignItems: 'center', justifyContent: 'center'}}
/>
</TouchableOpacity>
</View>
</View>
);
}
export default React.memo(CustomerNotes);
const styles = StyleSheet.create({
TextInputStyleClass: {
height: 45,
borderColor: '#0096FF',
flex: 7,
marginLeft: '4%',
marginRight: '4%',
flex: 1,
borderRadius: 6,
borderWidth: 1,
paddingLeft: 12,
fontFamily: 'Poppins-Medium',
fontSize: 14,
backgroundColor: 'white',
},
titleStyle: {
fontSize: 13,
color: '#000000',
fontFamily: 'Poppins-SemiBold',
},
subTitle: {
fontSize: 11,
fontFamily: 'Poppins',
color: '#000000',
},
});
I am fetching data from getNotes() API to render in Flatlist also I have a textinput at the bottom of the page. Whenever I submit textinput data to addNotes API data is added sucessfully and again I am calling getNotes API to reload the data in flatlist.
The issue is data rendering in flatlist is getting very slow and also the activityIndicator is not loading properly. When I call submitNotes the activityIndicator should start loading once the data is added and finished data rendering in flatlist the activityloader should stop loading.
To reload the flatlist each time the data changes you can pass extraData props. For performance optimizations, you can limit the number of items to be loaded at once using initialNumToRender, and onScroll more items will be loaded. Toggle refreshing props to true/false based on API response.
<FlatList
data={data.notesList}
renderItem={renderItem}
style={{marginTop: hp('1.5%')}}
keyExtractor={...}
extraData={data.noteList}
initialNumToRender={10}
refreshing={true}
/>

Trying to send image to heroku api but keep getting error 400

I'm trying to make an app that takes a picture and then returns the list of objects detected on that image. the code below is the whole code i'm using. i've changed the url of the api to 'insert api url here' just incase some troll find this post and spams the api with requests but i've made sure that the api url i'm using the correct one as i've tested it on postman and just copy pasted the api url.
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";
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);
}
}
};
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
axios
.post("insert api url here", {
Imagee: image,
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
alert("done");
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
type="submit"
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,
},
});
The part where it makes a post request the code snippet below.
so what i'm trying to do is store the uri of the image using state and then sending that uri
to the api using axios. i've made sure that the api is working on postman before testing it on my react native code but somehow i keep getting
[AxiosError: Request failed with status code 400]
I searched online as to what error 400 means and it says that it is an error caused by an invalid request which i find weird as the url is correct and i've done what every blog post or documentation axios has on post request has shown me.
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
axios
.post("insert api url here", {
Imagee: image,
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
alert("done");
setImage(null);
console.log("saved successfully");
} catch (error) {
console.log(error);
}
}
};

Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'camera.takePictureAsync') React-Native expo-camera

I am trying to create a function that will access my device's camera, and will allow me to take a picture, but I get the above error. I modeled this similar to requesting access to the camera roll and it works fine, but I cannot get it to work for the camera.
What may be causing this? Below is some of my code:
import * as ImagePicker from 'expo-image-picker' //I am using expo
import {Camera} from 'expo-camera'
export default function Photo(){
// Image Picker function start
useEffect(() => {
(async ()=> {
if (Platform.OS != 'web'){
const ( status !== 'granted') {
if(status !== 'granted) {
alert('Camera roll required to upload photo from your library');
}
}
})();
},[]);
//Image Picker function end
const camera = useRef(null) //added this
const takePicture = async () => { // added this
useEffect(() => {
(async () => {
if (Platform.OS !== 'web'){
const { status1 } = await Camera.requestPermissionsAsync();
if (status1 !== 'granted'){
alert('Camera required to take a photo');
}
} //added this
},
})();
}, [])
}
<Camera //added this
ref = { camera }
onGoogleVisionBarcodesDetected = {({barcodes}) => {
console.log(barcodes)
}}
/> //added this
<View style = {[ styles.button, {justifyContent: 'center', borderRadius: 20, backgroundColor: '#fff', paddingTop: 10, width: width*0.5, alignItems: 'center' } ]}>
<TouchableOpacity
color='#fff'
onPress = { ()=> takePicture () }
>
<Text style = {[ styles.button, {}]}>Take Photo </Text>
</TouchableOpacity>
</View>
This might help
import React, { useRef } from 'react'
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'
import { RNCamera } from 'react-native-camera'
function PlayWithCamera() {
const camera = useRef(null);
const takePicture = async () => {
const result1 = await camera.takePictureAsync();
....
};
return (
<View style={styles.container}>
<RNCamera
ref={camera}
.....
onGoogleVisionBarcodesDetected={({ barcodes }) => {
console.log(barcodes)
}}
/>
<View ... >
<TouchableOpacity
onPress={() => takePicture() } // change here
>
......
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
padding: 15,
paddingHorizontal: 20,
alignSelf: 'center',
margin: 20,
},
})
export default PlayWithCamera

How to lazy load with specific number of items in scrollview in react native?

I am trying to develop an app where a screen contains news feed loading data from a certain api which loads around 100 of the data. I would like to paginate it like first load 10 data then scroll more to get more data and so on.Which is also referenced as infinite scrolling.
You should use below example for pagination in scrollview or flatlist. Paste your url(API) here and run.
import React, { Component } from "react"
import {
View,
Text,
TouchableOpacity,
StyleSheet,
FlatList,
Platform,
ActivityIndicator
} from "react-native"
class FlatlistPagination extends Component {
constructor() {
super()
this.state = {
loading: true,
//Loading state used while loading the data for the first time
serverData: [],
//Data Source for the FlatList
fetching_from_server: false
//Loading state used while loading more data
}
this.offset = 1
//Index of the offset to load from web API
}
componentDidMount() {
fetch("http://aboutreact.com/demo/getpost.php?offset=" + this.offset)
//Sending the currect offset with get request
.then(response => response.json())
.then(responseJson => {
//Successful response from the API Call
this.offset = this.offset + 1
//After the response increasing the offset for the next API call.
this.setState({
serverData: [...this.state.serverData, ...responseJson.results],
//adding the new data with old one available in Data Source of the List
loading: false
//updating the loading state to false
})
})
.catch(error => {
console.error(error)
})
}
loadMoreData = () => {
//On click of Load More button We will call the web API again
this.setState({ fetching_from_server: true }, () => {
fetch("http://aboutreact.com/demo/getpost.php?offset=" + this.offset)
//Sending the currect offset with get request
.then(response => response.json())
.then(responseJson => {
//Successful response from the API Call
this.offset = this.offset + 1
//After the response increasing the offset for the next API call.
this.setState({
serverData: [...this.state.serverData, ...responseJson.results],
//adding the new data with old one available in Data Source of the List
fetching_from_server: false
//updating the loading state to false
})
})
.catch(error => {
console.error(error)
})
})
};
renderFooter() {
return (
//Footer View with Load More button
<View style={styles.footer}>
<TouchableOpacity
activeOpacity={0.9}
onPress={this.loadMoreData}
//On Click of button calling loadMoreData function to load more data
style={styles.loadMoreBtn}
>
<Text style={styles.btnText}>Load More</Text>
{this.state.fetching_from_server ? (
<ActivityIndicator color="white" style={{ marginLeft: 8 }} />
) : null}
</TouchableOpacity>
</View>
)
}
render() {
return (
<View style={styles.container}>
{this.state.loading ? (
<ActivityIndicator size="large" />
) : (
<FlatList
style={{ width: "100%" }}
keyExtractor={(item, index) => index}
data={this.state.serverData}
renderItem={({ item, index }) => (
<View style={styles.item}>
<Text style={styles.text}>
{item.id}
{"."}
{item.title.toUpperCase()}
</Text>
</View>
)}
ItemSeparatorComponent={() => <View style={styles.separator} />}
ListFooterComponent={this.renderFooter.bind(this)}
//Adding Load More button as footer component
/>
)}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingTop: 30
},
item: {
padding: 10
},
separator: {
height: 0.5,
backgroundColor: "rgba(0,0,0,0.4)"
},
text: {
fontSize: 15,
color: "black"
},
footer: {
padding: 10,
justifyContent: "center",
alignItems: "center",
flexDirection: "row"
},
loadMoreBtn: {
padding: 10,
backgroundColor: "#800000",
borderRadius: 4,
flexDirection: "row",
justifyContent: "center",
alignItems: "center"
},
btnText: {
color: "white",
fontSize: 15,
textAlign: "center"
}
})
export default FlatlistPagination

In react-native there is TypeError

'use strict';
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
TextInput,
Image
} from 'react-native';
var Forecast=require('./Forecast');
const APIKEY = "API KEY";
var WeatherProject = React.createClass({
//if you want to have a default zip code, 넌 여기에 넣을 수 있다.
getInitialState(){
return {
zip:'', //우편 번호
forecast: null
};
},
_handleTextChange(event){
var zip= event.nativeEvent.text;
this.setState({zip:zip});
fetch('http://api.openweathermap.org/data/2.5/weather?zip='
+zip+'.KR&units=metric&APPID='+APIKEY)
.then((response) => response.json())
.then((responseJSON) => {
this.setState({
forecast: {
main: responseJSON.weather[0].main,
description: responseJSON.weather[0].description,
temp: responseJSON.main.temp
}
});
})
.catch((error) => {
console.warn(error);
});
},
render(){
var content = null;
if( this.state.forecast!==null){
content = <Forecast
main={this.state.forecast.main}
description={this.state.forecast.description}
temp={this.state.forecast.temp}/>;
}
return(
<View style={styles.container}>
<Image
source = {require('./img/flower.jpeg')}
resizeMode='cover'
style={styles.backdrop}>
<View style={styles.overlay}>
<View style={styles.row}>
<Text style={styles.mainText}>
Current weather for
</Text>
<View>
<TextInput
style={styles.zipCode}
returnKeyType='go'
onSubmitEditing={this._handleTextChange}/>
</View>
</View>
{content}
</View>
</Image>
</View>
);
}
});
var baseFontSize = 16;
var styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingTop:5
},
backdrop: {
flex:1,
flexDirection:'column'
},
overlay:{
paddingTop:5,
backgroundColor:'#000000',
opacity:0.5,
flexDirection:'column',
alignItems:'center'
},
row:{
flex:1,
flexDirection:'row',
flexWrap:'nowrap',
alignItems:'flex-start',
padding:30
},
zipCode:{
width:70,
height:30,
marginLeft:5,
backgroundColor:'#FFFFFF',
fontSize:20,
padding:0,
color: '#000000'
},
mainText:{
flex:1,
fontSize:baseFontSize,
color:'#FFFFFF'
}
});
module.exports=WeatherProject;
In _handleTextChange(event) function
.then((response) => response.json())
.then((responseJSON) => {
this.setState({
forecast: {
main: responseJSON.weather[0].main,
description: responseJSON.weather[0].description,
temp: responseJSON.main.temp
}
});
})
in this code, TypeError: undefined is not an object(evaluating 'responseJSON.weather[0]') There is an error.. why this error occuered?
How can I exchange this code to execute normally?
Your error is occurring because you have left out a valid API key to query against the OpenWeatherMap API. The response that comes back for what you have written is:
{"cod":401, "message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info."}
Following this link will explain the requirement to set up an account and create an API key to use this service.
I created an account and API key with OpenWeatherMap, used your code sample, popping in a simple stateless component to dump out the props passed in to the Forecast component to verify this is all you need to correct your error.