ReactNative - get data from promise (JSON) - javascript

I am able to fetched the JSON data and it now returns an array. How do I use the elements in the array in react native? Below is my attempt:
export default function display() {
const fetching = async() => ... //defines fetching() which returns the array
...
return (
<View>
<Image
source = {{uri: 'http://imageURI.' + fetching().then((arr) => {return arr[0]}) + '.png'}}
style = {{height: 50, width: 50, borderRadius: 50}} />
</View>
)
}
How can I access the elements in the array?

Try the following.
You need to make your API call asynchronously, display something until you get the response and then update the state with retrieved data.
import React, {useState, useEffect} from 'react';
import {View, Image} from 'react-native'
const fetch = async () => {/* ASYNC LOGIC HERE*/};
const MyComponent = () => {
const [uri, setUri] = useState(null);
useEffect(() => {
fetch().then((arr) => {
setUri(`http://imageURI.${arr[0]}.png`);
});
}, []);
return (
<View>
{
uri ? <Image source={{uri}} style={{height: 50, width: 50, borderRadius: 50}} /> : null
}
</View>
);
};

I agree with ernesto, I would just do all my logic in the fetching function and for me if you get an array it is for several elements so I would prepare that with a map method
import React, { useState, useEffect } from "react";
import { View, Image } from "react-native";
const Display = () => {
const [state, setState] = useState(null);
const fetching = async () => {
try {
const response = await fetch("api.exemple");
const imagesArray = await response.json();
setState(imagesArray);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
fetching();
}, []);
return (
<View>
{state &&
state.map((fileName) => {
const uri = `http://imageURI.${fileName}.png`;
return (
<Image
source={{ uri }}
style={{ height: 50, width: 50, borderRadius: 50 }}
/>
);
})}
</View>
);
};
export default Display;

Related

Inability to get data from API react native

Hi so my main question is when making a api call to https://newsdata.io, i want to access the results method on the object the api returns. However react native is saying results is undefined. Why cant i see the data object but not the methods attached to the data variable.
import React from 'react'
import { Text, View, Image } from 'react-native'
export const Feed = () => {
async function data() {
const response = await fetch('https://newsdata.io/api/1/news?apikey=pub_11306c8c5e2932eab7155edacbc6339247174&q=web%203')
const data = await response.json()
const results = data.results;
const imageURLDATA = results.forEach(element => {
console.log(element.image_url)
})
}
data()
return (
<View>
<Text style={{fontSize: 40, fontWeight: "700", marginTop: 20}}>Feed</Text>
{results.forEach(element => {
<View>
< Image source={{
uri: `${element.image_url}`
}}/>
</View>
})}
</View>
)
}
You need to take the component lifecycle into consideration. Use useState to create a variable that trigger component rerenders and useEffect to call functions at certain events:
import React, { useState, useEffect } from 'react';
import { View, Image, Text } from 'react-native';
export const Feed = () => {
const [feedData, setFeedData] = useState([]);
async function getData() {
// you may want to change your api key
const response = await fetch(
'https://newsdata.io/api/1/news?apikey=pub_11306c8c5e2932eab7155edacbc6339247174&q=web%203'
);
const data = await response.json();
const results = data.results;
setFeedData(results);
}
//will call provided function when items in array is updated
useEffect(() => {
console.log('Feed data updated')
feedData.forEach((element) => {
console.log(element.image_url);
});
}, [feedData]);
// will call provided function once after first render
useEffect(() => {
getData();
}, []);
return (
<View>
<Text style={{ fontSize: 40, fontWeight: '700', marginTop: 20 }}>
Feed
</Text>
{/*forEach returns null, map returns value*/}
{feedData.map((element) => (
<View>
<Image
source={{
uri: `${element.image_url}`,
}}
// provide width to element or it wont render
style={{width:100,height:100}}
/>
</View>
)
)}
</View>
);
};
export default Feed;
Here's a demo

How to filter Firebase Firestore Array data in React native app?

I want to fetch only values of '1' and '3' from the Arraytesting(array part). Please check the Image so that you will understand my question. Can I solve this by coding inside Flatlist part or do I need to change the Firestore data fetching method?
And if I fetch data from Array there should not be an empty field for the remaining value of 0, 2. Yesterday I posted a question that question was similar to this question but this time I am trying to fetch only array data. #DrewReese supported me on that problem. Please check my previous question link- React Native Firebase Firestore data not fetching properly
import React, { useState, useEffect } from 'react';
import { ActivityIndicator, FlatList, View, Text } from 'react-native';
import {firebase} from '../config';
const Testing = ({ navigation }) =>{
const [loading, setLoading] = useState(true); // Set loading to true on component mount
const [users, setUsers] = useState([]);
useEffect(() => {
const subscriber = firebase.firestore()
.collection('testing')
.onSnapshot(querySnapshot => {
const users = [];
querySnapshot.forEach(documentSnapshot => {
users.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setUsers(users);
setLoading(false);
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
if (loading) {
return <ActivityIndicator />;
}
return (
<FlatList
data={users}
renderItem={({ item }) => (
<View style={{ height: 50, flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>ID: {item.One}</Text>
<Text>Name: {item.five}</Text>
</View>
)}
/>
);}
export default Testing;
Hey you can try something like this :
filtering out for index 1 and index 3
import React, { useState, useEffect } from 'react';
import { ActivityIndicator, FlatList, View, Text } from 'react-native';
import {firebase} from '../config';
const Testing = ({ navigation }) =>{
const [loading, setLoading] = useState(true); // Set loading to true on component mount
const [users, setUsers] = useState([]);
const [filteredusers, setFiltered] = useState([])
useEffect(() => {
const subscriber = firebase.firestore()
.collection('testing')
.onSnapshot(querySnapshot => {
const users = [];
querySnapshot.forEach(documentSnapshot => {
users.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setUsers(users);
//setting here
const newFiltered = users?.filter((data,index) => (index === 1 || index ===3) );
setFiltered(newFiltered)
setLoading(false);
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
if (loading) {
return <ActivityIndicator />;
}
return (
<FlatList
data={filteredusers} // users is now filtered
renderItem={({ item }) => (
<View style={{ height: 50, flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>ID: {item?.id}</Text>
<Text>Name: {item?.name}</Text>
</View>
)}
/>
);}
export default Testing;

using Onclick, fetch api data in react native

I am new to React Native.
I am facing an issue with this view. Basically it is something like this when you click a button it generates any random number, now this random number becomes an id and it goes to at the end of the API url, And using this new API - with ID at the end of it. - data gets fetched. Now i've divided this task in two parts generating random number code (i.e. snippet 1) and fetching data from api ( i.e. snippet 2). As of now, I don't know how to combine them because i am new to react native so a little help here would be appreciated from anyone.
Snipppet 1
import { StyleSheet, View, Button, Text } from 'react-native';
export default class MyProject extends Component {
constructor(){
super();
this.state={
// This is our Default number value
NumberHolder : 0
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1 ;
this.setState({
NumberHolder : RandomNumber
})
}
render() {
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
Snippet 2
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const fetchData = async () => {
const resp = await fetch("https://jsonplaceholder.typicode.com/photos/7");
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
Thanks in advance!!
I think you must understand components clearly! React is component based! But your case is not 2 components! You have a component for fetching api and showing in list! Generating a random number is not a component, but it is a method(or function) in your list component! I think it is better to use one component for list and wrap a function to it for generating random number.
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const generatRandomNumber = () => {
return Math.floor(Math.random() * 5000) + 1
}
const fetchData = async () => {
const resp = await fetch(`https://jsonplaceholder.typicode.com/photos/${generatRandomNumber()}`);
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
But if you want to passing data between components you are have, it is not related to function or class component and you can pass data between them with props! So your code like this:
Random Number Component
import { StyleSheet, View, Button, Text } from 'react-native';
export default class MyProject extends Component {
constructor(props){ //edited
super(props); //edited
this.state={
// This is our Default number value
NumberHolder : 0
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1 ;
this.props.randomNumber(RandomNumber)
}
render() {
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
Your list component:
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
// import MyProject
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const [number, setNumber] = useState(null);
const fetchData = async () => {
const resp = await fetch(`https://jsonplaceholder.typicode.com/photos/${number}`);
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
<MyProject radomNumber={(number) => setNumber(number)}
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
thanks everyone for helping me.
here i am posting answer to my question, if anybody in future need an answer.
import React, { useEffect, useState, Component } from 'react';
import { StyleSheet, View, Button, FlatList, Text, Image } from 'react-native';
export default class MyProject extends Component {
constructor(){
super();
this.state={
// This is our Default number value
NumberHolder : 1,
books: []
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1;
fetch(`https://jsonplaceholder.typicode.com/photos/${RandomNumber}`)
.then((response) => response.json())
.then(booksList => {
this.setState({ books: booksList });
});
this.setState({
NumberHolder : RandomNumber
})
}
render() {
let Image_Http_URL ={ uri: 'https://reactnativecode.com/wp-content/uploads/2017/05/react_thumb_install.png'};
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Image
style={{width: '100%', height: 200,resizeMode : 'stretch' }}
source={{uri: this.state.books.url}}
/>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.title}</Text>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.url}</Text>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.thumbnailUrl}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});

(React Native) Setting AsyncStorage value but getting garbage when I retrieve it

I am trying to persist login info of a user in AsyncStorage (React Native), so that they don't have to login when they launch the app again. I have the code in place which should do that, but when I try to retrieve the value later, it's showing {"_U": 0, "_V": 0, "_W": null, "_X": null}, which looks like garbage value. What could I possibly be doing wrong here?
My code (styles omitted for clarity):
App.js
import React, { useEffect } from "react";
import AsyncStorage from "#react-native-community/async-storage";
import { Text, Button } from "react-native";
import Login from "./components/Login";
import Constants from "./libs/constants";
const App = () => {
const onLogin = async (e) => {
if (e.success)
await AsyncStorage.setItem(Constants.LOCAL_KEY, JSON.stringify(e));
};
const logoutDone = async () => {
await AsyncStorage.removeItem(Constants.LOCAL_KEY);
};
useEffect(() => {
console.log({ userData: AsyncStorage.getItem(Constants.LOCAL_KEY) });
// this shows {"_U": 0, "_V": 0, "_W": null, "_X": null}}
}, []);
const isLoggedIn = () => {
let userJSON = AsyncStorage.getItem(Constants.LOCAL_KEY);
return (
userJSON != undefined && JSON.parse(userJSON).EmployeeId != undefined
);
};
return !isLoggedIn() ? (
<Login onLogin={onLogin} />
) : (
<>
<Text>{JSON.stringify(AsyncStorage.getItem(Constants.LOCAL_KEY))}</Text>
<Button
title="Logout"
onPress={() => {
logoutDone();
}}
></Button>
</>
);
};
export default App;
Login.js
import Constants from '../libs/constants';
import React, {useState} from 'react';
import {
ScrollView,
View,
Text,
StatusBar,
TextInput,
TouchableOpacity,
} from 'react-native';
const Login = ({onLogin}) => {
const [Username, setUsername] = useState('');
const [Password, setPassword] = useState('');
const doLogin = () => {
fetch(Constants.LOGIN_API_URL, {
method: 'post',
body: JSON.stringify({Username, Password}),
})
.then((r) => r.json())
.then((s) => {
onLogin(s);
});
};
return (
<ScrollView>
<StatusBar hidden={true} />
<View style={{padding: 0, margin: 0}}>
<View style={{padding: 30}}>
<TextInput
onChangeText={(text) => setUsername(text)}></TextInput>
<TextInput
onChangeText={(text) => setPassword(text)}></TextInput>
<TouchableOpacity style={styles.button} onPress={() => doLogin()}>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
<Text style={styles.buttonText}>Sign In</Text>
</View>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
};
export default Login;
That is because AyncStorage.getItem returns a promise so you have to await or add a callback. Please update the following piece of your code
useEffect(() => {
console.log({ userData: AsyncStorage.getItem(Constants.LOCAL_KEY) });
// this shows {"_U": 0, "_V": 0, "_W": null, "_X": null}}
}, []);
to this
useEffect(() => {
const storage = async()=>{
let items = await AsyncStorage.getItem(Constants.LOCAL_KEY);
console.log(items)
}
storage()
}, []);
Note: Since useEffect doesn't accept an async function we have to declare an async method inside useEffect and execute it immediately.
Use
await Asyncstorage.getItem(Constants.LOCAL_KEY)
in Hooks you can write like that
useEffect(() => {
const retrieveData = async() => {
let items = await AsyncStorage.getItem(Constants.LOCAL_KEY);
console.log(items)
}
retrieveData()
}, []);

How do i style mapped data in a function in react native

How is styling done after mapping data into a function in react native. The data is displayed correctly but in a raw format. I'd like the data being mapped to be styled into rows with space between each item. I have tried using a flatlist and it throws an error of invariant violation: tried to get frame for out of the range index nan. Kindly help.
import React, {useEffect, useState} from 'react'
import { Text, View, ActivityIndicator, ScrollView, StyleSheet } from 'react-native'
import axios from '../../utils/axios'
//import CurrencyPair from '../../CurrencyPair'
function HomeScreen() {
const [data, setData] = useState([])
const [isLoading, setIsloading] = useState(true)
useEffect(() => {
const interval = setInterval(() => {
const fetchpairs = async() => {
const results = await axios.get('/v3/accounts/{AccountId}/pricing?instruments=AUD_CAD%2CAUD_CHF%2CAUD_JPY%2CAUD_NZD%2CAUD_USD%2CCAD_CHF%2CCAD_JPY%2CCHF_JPY%2CEUR_AUD%2CEUR_CAD%2CEUR_CHF%2CEUR_GBP%2CEUR_NOK%2CEUR_NZD%2CEUR_USD%2CGBP_AUD%2CGBP_CAD%2CGBP_CHF%2CGBP_USD%2CGBP_JPY%2CNZD_CAD%2CNZD_CHF%2CNZD_JPY%2CUSD_CAD%2CUSD_JPY%2CUSD_CHF%2CUSD_ZAR%2CUSD_MXN')
console.log(results.data)
setData(results.data)
setIsloading(false)
}
fetchpairs()
},1000)
}, []);
if(isLoading) {
return (
<ActivityIndicator size="large"/>
)
}
else
return (
<ScrollView
contentContainerStyle={styles.contentContainer}
>
{data.prices && data.prices.map((prices, index) => {
return (
<Text key={index} style={styles.maintext}>
{data.prices[index].instrument}
{data.prices[index].closeoutAsk}
{data.prices[index].closeoutBid}
</Text>
)
})
}
</ScrollView>
)
}
const styles = StyleSheet.create({
contentContainer:{
flex: 1,
marginTop: 20,
justifyContent: "space-around"
}
})
export default HomeScreen
Just use flex to style.
{data.prices && data.prices.map((prices, index) => {
return (
<View
key={index}
style={{
flexDirection: 'row'
//justifyContent:'space-between'
}}>
<Text style={styles.maintext}>{data.prices[index].instrument}</Text>
<Text style={(styles.maintext, { marginLeft: 4 })}>{data.prices[index].closeoutAsk}</Text>
<Text style={(styles.maintext, { marginLeft: 4 })}>{data.prices[index].closeoutBid}</Text>
</View>
)
})
}

Categories