I'm trying to display data from an api and cant get a hold of using the forEach method correctly to show all the data at the same time. The API is working correctly. Here's the code:
import React, {useEffect, useState} from 'react'
import { Text, View, ActivityIndicator, ScrollView } 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 fetchpairs = async() => {
const result = await axios.get('/v3/accounts/{AccountId}/pricing?instruments=EUR_USD%2CUSD_CAD')
console.log(result.data)
setData(result.data)
setIsloading(false)
}
fetchpairs()
}, [])
if(isLoading) {
return (
<ActivityIndicator size="large"/>
)
}
else
return (
<ScrollView>
{[data].map((data) => (
data.forEach(data =>{
<Text>{JSON.stringify(data.prices[0].instrument)}
{JSON.stringify(data.prices[0].closeoutAsk)}
{JSON.stringify(data.prices[0].closeoutBid)}
</Text>
})
))}
</ScrollView>
)
}
export default HomeScreen
Map is already taking care of forEach function
<ScrollView>
{[data].map((item,i) => {
return(<Text key={i}>{JSON.stringify(item.prices[0].instrument)}
{JSON.stringify(item.prices[0].closeoutAsk)}
{JSON.stringify(item.prices[0].closeoutBid)}
</Text>
)}
)}
</ScrollView>
Related
THE CODE USING REACT-NATIVE AND EXPO-LOCATION:
import {
View,
Text,
Alert,
SafeAreaView,
RefreshControl,
StyleSheet,
ActivityIndicator,
ScrollView
} from 'react-native';
import React, {
useEffect,
useState
} from 'react';
import * as Location from 'expo-location'
const openWeatherKey = 'cbb62d0f2653b471dbf6ca28aebb813f'
let url = `http://api.openweathermap.org/data/2.5/onecall?&units=metric&exclude=minutely&appid=${openWeatherKey}`
const Weather = () => {
const [forecast, setForecast] = useState(null)
const [refreshing, setRefreshing] = useState(false)
const loadForecast = async () => {
setRefreshing(true)
const {
status
} = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Permission to acces location was denied')
}
let location = await Location.getCurrentPositionAsync({
enableHighAccuracy: true
})
const response = await fetch(`${url}&lat=${location.coords.latitude}&lon=${location.coords.longitude}`)
const data = await response.json()
if (!response.ok) {
Alert.alert('error something went wrong')
} else {
setForecast(data);
}
setRefreshing(false)
}
useEffect(() => {
loadForecast()
}, [])
if (!forecast) {
return (
<SafeAreaView style={styles.loading}>
<ActivityIndicator size='large'/>
</SafeAreaView>
)
}
const current = forecast.current.weather[0]
return (
<SafeAreaView style={styles.container}>
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing} onRefresh={() => loadForecast()}/>
}
style={{marginTop:50}}
>
<Text style={styles.title}>
Current Weather
</Text>
<Text style={{alignItems:'center', textAlign:'center'}}>
Your Location
</Text>
<View>
</View>
</ScrollView>
</SafeAreaView>
)
}
export default Weather
)
THE ERROR: 'Error something went wrong'
But i dont understand why he is not able to get the location?
Does somebody know the answer? i think it goes wrong at const response. Also when i use the standard Code for gettting a location from expo-location docs it works?
Render Error:
(0,_reactNative.usestate) is not a function.(In'(0,_reactNative.useState)(''),'(0,_reactNative.useState)'is undefined
This is the error my code is producing. All the imports are up to date. Not sure why it is not recognizing useState.
import React from 'react';
import { View, StyleSheet,TextInput,useEffect,useState } from 'react-native';
import db from 'D:/App development/PRLog/PrLogBeta/database/firestore'
const EnteryModal = props => {
const [numReps,setNumReps] = useState('');
useEffect(() => {
db.collection('Bench').add({reps:{newNum}})
},[]).then(() => {
console.log('Number Added!');
});
return(
<View style={styles.inputStyle}>
<form>
<TextInput
style = {styles.inputStyle}
keyboardType='number-pad'
placeholder={props.RepsOrWeight}
placeholderTextColor = 'white'
textAlign='center'
onChangeText={newNum => setNumReps(newNum)}
defaultValue={numReps}
onSubmitEditing={useEffect(() => {
db.collection('Bench').add({reps:{newNum}})
},[]).then(() => {
console.log('Number Added!');
})}
>
</TextInput>
</form>
</View>
);
};
You need to import useState and useEffect from React, not React Native
You cannot call .then() on useEffect since it does not return a promise.
You can't use useEffect as a callback function.
EDIT: Code example:
Based on the snippet from your question, it seems like you're trying to trigger a POST request to your database on submitting the text input. This can be achieved without useEffect by simply passing a handler function to your text input like so.
import React, { useEffect, useState } from 'react';
import { View, StyleSheet,TextInput } from 'react-native';
import db from 'D:/App development/PRLog/PrLogBeta/database/firestore'
const EnteryModal = props => {
const [numReps,setNumReps] = useState('');
const handleSubmit = async () => {
try {
await db.collection('Bench').add({reps:{newNum}});
console.log('Number Added!');
} catch (error) {
console.log(error)
}
}
return(
<View style={styles.inputStyle}>
<form>
<TextInput
style = {styles.inputStyle}
keyboardType='number-pad'
placeholder={props.RepsOrWeight}
placeholderTextColor = 'white'
textAlign='center'
onChangeText={newNum => setNumReps(newNum)}
defaultValue={numReps}
onSubmitEditing={handleSubmit}
>
</TextInput>
</form>
</View>
);
};
Use useState and useEffect as a react component not as react native component.
as shown in below example.
import React, { useEffect, useState } from 'react';
import { View, StyleSheet, TextInput} from 'react-native';
import db from 'D:/App development/PRLog/PrLogBeta/database/firestore'
const EnteryModal = props => {
const [numReps, setNumReps] = useState('');
useEffect(() => {
dataBaseCollection();
console.log("Number Added!");
}, []);
const dataBaseCollection = () => {
db.collection('Bench').add({ reps: { newNum } });
}
return (
<View style={styles.inputStyle}>
<form>
<TextInput
style={styles.inputStyle}
keyboardType='number-pad'
placeholder={props.RepsOrWeight}
placeholderTextColor='white'
textAlign='center'
onChangeText={newNum => setNumReps(newNum)}
defaultValue={numReps}
onSubmitEditing={(event) => {
dataBaseCollection();
}}
>
</TextInput>
</form>
</View>
);
};
I get my data from firebase, push the data into an array and render the items in flatlist component. What did i miss?
but list render the items only for a really short time.
import React, { useState, useEffect } from 'react';
import { FlatList, Box } from "native-base";
import { StyleSheet } from 'react-native'
import EventCard from "./EventCard.js";
import { LogBox } from 'react-native';
import { ActivityIndicator } from 'react-native';
import { getFirestore, collection, getDocs } from 'firebase/firestore';
// Silent warning about https://github.com/facebook/react-native/issues/12981
LogBox.ignoreLogs(['Setting a timer']);
export default function Events() {
const [loading, setLoading] = useState(true);
const [events, setEvents] = useState({});
useEffect(() => {
let eventData = []
const firestore = getFirestore();
const querySnapshot = getDocs(collection(firestore, 'events'));
querySnapshot.then(querySnapshot => {
querySnapshot.docs.map(doc => {
eventData.push(doc.data())
setEvents(eventData)
})
});
setLoading(false);
}, []);
if (loading) {
return <ActivityIndicator />;
}
return (
<Box style={styles.container}>
<FlatList
data={events}
keyExtractor={item => item.key}
renderItem={({ item }) => (<EventCard key={Date.now()} eventData={item} />
)}
/>
</Box>
);
}
const styles = StyleSheet.create({
container: {
alignSelf: 'stretch',
alignItems: 'center'
},
})
Thanks for your time. i really stuck.
You have setEvents(eventData) in the map() so after every iteration the state is being updated. Instead parse the data and then update state once.
querySnapshot.then(querySnapshot => {
querySnapshot.docs.map(doc => {
eventData.push(doc.data())
})
// After iterating over all docs
setEvents(eventData)
});
This is where my home screen is:
import React, { useState } from "react";
import {
StyleSheet,
View,
Text,
Button,
FlatList,
TouchableOpacity,
} from "react-native";
import { globalStyles } from "../styles/global";
import Card from "../shared/card";
import FlatButton from "../shared/button";
import { TextInput } from "react-native-gesture-handler";
import { AntDesign } from "#expo/vector-icons";
import Weather from "./weather";
export default function Home({ navigation }) {
//add state here
const [reviews, setReviews] = useState([
{ title: "Let's Snowboard", rating: 4, body: "blue", key: 1 },
]);
const [city, setCity] = useState("");
return (
<View style={globalStyles.container}>
<View style={styles.searchBox}>
<TextInput
placeholder="search"
placeholderTextColor="lightcoral"
style={styles.searchText}
onChange={(text) => setCity(text)}
/>
<TouchableOpacity style={styles.buttonTouch} onPress={Weather}>
<AntDesign name="search1" size={28} color="lightcoral" />
</TouchableOpacity>
</View>
<FlatList
data={reviews}
renderItem={({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("Weather", item)}
>
<Card>
<Text style={globalStyles.titleText}>{item.title}</Text>
</Card>
</TouchableOpacity>
)}
/>
<FlatButton text="Let's snowboard?" />
</View>
);
}
For my weather screen:
import React, { useState } from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import { globalStyles } from "../styles/global";
const Weather = () => {
const [date, setData] = useState([]);
const [icon, setIcon] = useState("");
const [cityDisplay, setCityDisplay] = useState("");
const [desc, setDesc] = useState("");
const [main, setMain] = useState("");
const [humidity, setHumidity] = useState("");
const [pressure, setPressure] = useState("");
const [visibility, setVisibility] = useState("");
const [temp, setTemp] = useState("");
async function fetchWeather() {
try {
const response = await fetch(
"https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=***"
);
const json = await response.json();
setData({ data: json });
setTemp({ temp: (json.main.temp - 273.15).toFixed(2) + " C" });
setCityDisplay({ cityDisplay: json.name });
setIcon({ icon: json.weather[0].icon });
setMain({ main: json.weather[0].main });
setHumidity({ humidity: json.main.humidity + " %" });
setPressure({ pressure: json.main.pressure + " hPa" });
setVisibility({
visibility: (json.visibility / 1000).toFixed(2) + " km",
});
} catch (err) {
console.warn("error");
}
}
return (
<View style={styles.weatherBox}>
<View style={styles.weatherHolder}>
<Image
source={{
uri: "http://openweathermap.org/img/wn/" + setIcon + "#2x.png",
}}
style={styles.weatherImage}
/>
<View>
<Text style={styles.temperature}>{temp}</Text>
<Text>{cityDisplay}</Text>
</View>
</View>
</View>
);
};
Essentially, my goal is to click the card text where it says :let's snowboard. Once clicked, it should redirect me to the weather screen where at the moment, it will show me the current temperature and the name of the city. I am not sure why it's not showing. Im assuming it has something to do with my weather screen.
I had tested out making another simple screen where it would show the values of my current state 'reviews'. I was able to click the card and redirect me to another screen where it shows the rating value and the body.
This is the first time I've dealt with apis. Any guidance would be much appreciated(:
I am fairly certain that you do not actually call the fetchWeather function. In the Weather component you define the function with async function fetchWeather() {...}. However, that is only a function definition. You need to actually call it like this: fetchWeather(); which I think you can do right below the definition like the example below.
async function fetchWeather() {
// code that you want to execute in the function
}
// Actual function call
fetchWeather();
EDIT (concerning state management):
I would definitely recommend reading most of the React Hooks documentation to get a full grasp, but I will still address how you handle state.
At this location in the docs it shows exactly what I believe your issue to be.
Whenever you try to set state you do this: setVariable({ variableName: newValue});, but that is how you are supposed to set state inside of a class. However, fetchWeather() is a function, and functions are supposed to update state like this: setVariable(newValue);
I am learning how to use React Hooks and have been stuck for many hours on something that's supposed to be very simple.
I am trying to display a a text if the state variable "loading" is true. If it's false, I want to display something else.
No matter what I try, "loading" is always false or at least, the UI does not appear to reflect its value.
here is the code:
import React, {useState, useEffect} from 'react';
import {View, SafeAreaView, Text} from 'react-native';
const testScreen= (props) => {
const [loading, setLoading ] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
if(loading)
{
return <Text>Hi</Text>;
}
else
{
return<Text.Hey</Text>
}
}
export default testScreen;
Any help will be more than welcome and I am sorry if this is very basic.
UPDATE: Here is the actual code I am working with. SetLoading is supposed to update the state variable to false but never does or at least, the UI des not render.
import React, {useState, useEffect} from 'react';
import {View, SafeAreaView, Text, ActivityIndicator} from 'react-native';
import CategoryTag from '../Components/CategoryTag';
import firestore from '#react-native-firebase/firestore';
const CategoryScreen = (props) => {
const topicCollection = firestore().collection('Topics')
.where("active","==",true);
//hooks for topics
const [topics,setTopics] = useState([]);
const [loading, setLoading ] = useState(true);
//get all active topics
useEffect(() => {
return topicCollection.onSnapshot(querySnapshot => {
const list = [];
querySnapshot.forEach(doc => {
const { active, name } = doc.data();
list.push({
id: doc.id,
active,
name,
});
});
setTopics(list);
setLoading(false);
});
}, []);
const renderTopics = () =>{
return(
topics.map((item) =>{
return(
<CategoryTag key = {item.id}
color={userTopics.includes(item.name) ?"#51c0cc":"#303239"}
name = {item.name}
isSelected = {userTopics.includes(item.name)}
handleClick = {addTopicToUserTopicCollection}
/>
)
})
)
}
if(loading)
{
return (
<SafeAreaView style={{flex:1, backgroundColor:"#455a65"}}>
<View style={{width:200, padding:20, paddingTop:60}}>
<Text style ={{fontSize:25, fontWeight:"bold",
color:"#fff"}}>What are you</Text>
<Text style ={{fontSize:22, color:"#fff"}}>interested in?
</Text>
</View>
<View style={{flex:1, alignItems:"center",
justifyContent:"center", alignSelf:"center"}}>
<ActivityIndicator />
</View>
</SafeAreaView>
)
}
else // this never runs
{
return (
<SafeAreaView style={{flex:1, backgroundColor:"#455a65"}}>
<View>
<View style={{width:200, padding:20, paddingTop:60}}>
<Text style ={{fontSize:25, fontWeight:"bold",
color:"#fff"}}>What are you</Text>
<Text style ={{fontSize:22, color:"#fff"}}>interested in?
</Text>
</View>
<View style ={{flexDirection:"column", paddingTop:20}}>
<View style ={{padding:15, paddingTop:15,
marginBottom:15,
flexWrap:"wrap", flexDirection:"row"}}>
{renderTopics(topics)}
</View>
</View>
</View>
</SafeAreaView>
);
}
}
export default CategoryScreen;
You are immediately setting your setLoading state to false and therefore loading text might be rendering for fraction of second, or not at all, like a glitch. Try setting setLoading with a timeout and then you will see the intended behaviour.
const TestScreen= (props) => {
const [loading, setLoading ] = useState(true);
useEffect(() => {
setTimeout(()=>setLoading(false), 3000);
}, []);
if(loading)
{
return <Text>Hi</Text>;
}
else
{
return<Text>hey</Text>
}
}