I'm using fetch() to get data from an external data and want to display it in my View.
console.log(responseJson) is displaying data from the API, but this.state.data in my <Text> is not showing it.
All shown in my app is "Temperatur: C".
Not getting any errors when I'm running it.
Is my this.state.data not the correct way to show it?
import React, { Component } from 'react'
import { StyleSheet, Text, View, Image, Button, Alert } from 'react-native';
class Wether extends Component {
state = {
data: ''
}
componentDidMount = () => {
fetch('https://opendata-download-metfcst.smhi.se/api/category/pmp2g/version/2/geotype/point/lon/16/lat/58/data.json',{
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View>
<Text>
Temperatur: {this.state.data} C
</Text>
</View>
)
}
}
export default Wether
My console.log(responseJson) shows:
Object {
"parameters": Array [
Object {
"level": 0,
"levelType": "hmsl",
"name": "msl",
"unit": "hPa",
"values": Array [
1005,
],
},
As I have checked your code, seem everything is fine.
Just one thing you should consider is your response JSON Data Object.
You should not display your Response JSON-Data into display in Text Component
<View style={{flex:1, alignItems:'center', justifyContent:'center'}}>
<Text>
Temperatur: { this.state.data.approvedTime } C
</Text>
</View>
Please recheck your code again, hope it could help.
You should initialize state in the constructor, and you can us this.setState() everywhere else.
import React, { Component } from 'react'
import { StyleSheet, Text, View, Image, Button, Alert } from 'react-native';
class Wether extends Component {
constructor(props) {
super(props);
state = {
data: ''
}
}
componentDidMount = () => {
fetch('https://opendata-download-metfcst.smhi.se/api/category/pmp2g/version/2/geotype/point/lon/16/lat/58/data.json',{
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View>
<Text>
Temperatur: {this.state.data} C
</Text>
</View>
)
}
}
export default Wether
Related
I need to fetch an api and get the these data from one file in React native, I am able to get the data in the file that fetch the api by console.log()
API.js
export const merchastListFetch = [
axios.get('http://myapi.com/API/fetch_all')
.then(function (response) {
// console.log(response.data);
//able to get the data here
return response.data;
})
]
Merchant_list.js
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import MerchantItem from './MerchantItem'
import { FlatList, TouchableOpacity } from 'react-native-gesture-handler'
import { merchant } from '../../models/models'
import SectionHeader from './SectionHeader'
import { H4, P } from '../typography'
import { merchastListFetch } from '../../API/api'
//get the api from the file
export default function MerchantList({navigation}) {
const renderItem = ({item})=> <MerchantItem {...item}/>
console.log({merchastListFetch});
//cannot access the data here
//get the data like this {"merchastListFetch": [{"_U": 0, "_V": 1, "_W": [Object], "_X": null}]}
return (
<View style={styles.sectionContainer}>
{/* <View style={styles.headerContainer}>
<H4 style={styles.textTitle}>Nearby Merchants</H4>
<View style={styles.flexContainer}>
<P style={styles.textDescription}>Pick from here get the fastest delivery</P>
<TouchableOpacity onPress={() => navigation.navigate('MerchantCategoryScreen')}>
<P style={styles.textLink}>See All</P>
</TouchableOpacity>
</View>
</View> */}
<SectionHeader title="Nearby Merchants" description="Pick from here get the fastest delivery" onLinkPress={() => navigation.navigate('MerchantCategoryScreen')}/>
<FlatList
keyExtractor={(item)=>item.merchant_id}
data={merchant}
renderItem={renderItem}
// itemDimension={80}
/>
</View>
)
}
What i expected from the Merchant_list.js
is the data like how i get in the API.js
which is format like this
{"status":true,"data":[{"shop_id":"1","merchant_id":"1","area_id":"0","agent_id":"1","business_type_id":"1","business_category_id":"1","bill_type_id":"1","currency_id":"0","status_id":"0","register_name":"Dummy Name","register_no":"123456789","retail_name":"Test Only","description":"TESTING USE","commission":"20.00","gst_no":"12345","coming_soon":"0","is_halal":"0","is_active":"1","delivery_charge":"3.50","remarks":"TESTING USE AGAIN","approved_date":"0000-00-00 00:00:00","deleted":"0","created_date":"2020-10-06 15:02:20","created_by":"1","modified_date":"2020-10-08 09:37:53","modified_by":"1","merchant":"Merchant","shop_image":[{"shop_image_id":"3","shop_id":"1","file":"\/images\/shop\/5af16e1c6554160a79bea005.png","file_size":"65124","file_type":"image\/png","is_default":"1","is_active":"1","deleted":"0","created_date":"2020-10-09 13:21:23","created_by":"0","modified_date":"0000-00-00 00:00:00","modified_by":"0"}]},
I did some reseach online and found out it possibly will be the aysnc and await issue , but i don know how to modified the code .
Any help will be appreciated !
You could save the response in an Array State and then call and modify it where you need it I guess.
Something like this:
async CallApiFunc(){
await fetch("http://myapi.com/API/fetch_all")
.then(res => res.json())
.then(res => {
console.log(JSON.stringify(res))
this.setState({
dataArray: res
})
})
.catch(err => console.log(err))
}
this requires a dataArray:[] as state.
After that you can show the entrys in a FlatList for example and also modify them like you do with state.
Modify your function as following.
export const merchastListFetch = ()=>{
return axios.get('http://myapi.com/API/fetch_all')
.then(function (response) {
return response.data;
}).catch((error)=>{
console.log(error)
})
}
I am new to React Native and practicing by creating a project which makes requests from a COVID-19 API. However, when I run my code, I get this error:
TypeError: undefined is not an object (evaluating 'this.state.data.confirmed.value')
import React from 'react';
import { View, Text } from 'react-native';
class TrackerScreen extends React.Component {
state = {
data: ''
}
componentDidMount = () => {
fetch('https://covid19.mathdro.id/api', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View>
<Text>
{this.state.data.confirmed.value}
</Text>
</View>
)
}
}
export default TrackerScreen;
I converted my componentDidMount to an arrow function as suggested by other members on an old thread but that did not get rid of the error. Does anybody have a solution to this issue? Any help would be appreciated. Thank you!
The first render will happen before the componentDidMount will be called. So, during the first render the data property from your state will be an empty string. And the code inside the render function is trying to access a nested prop. Either provide a more described state, like:
state = {
data: { confirmed: { value: null } }
}
or check the value inside the render function:
import React from 'react';
import { View, Text } from 'react-native';
class TrackerScreen extends React.Component {
state = {
data: ''
}
componentDidMount = () => {
fetch('https://covid19.mathdro.id/api', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
const { data: {confirmed: { value } = { value: null } } } = this.state
return value ? (
<View>
<Text>
{value}
</Text>
</View>
): null;
}
}
export default TrackerScreen;
You probably don't want to render anything if the data isn't present at the moment, so an additional check for the value will handle that
I have a class used to render a list of users from a database
export default class Users extends React.Component {
constructor() {
super()
this.state = {
data : [] //define a state
}
}
renderUsers = () => {
useEffect(() => {
fetch('exemple.com')
.then((response) => response.json())
.then((json) => this.setState({data: json.result})) // set returned values into the data state
.catch((error) => console.error(error))
}, []);
return this.state.data.map((value,key)=>{ // map state and return some views
......
})
}
render() {
return (
<View style={{ flex: 1 }}>
{this.renderUsers()} //render results
</View>
);
}
}
The problem is this code will throw the following error :
Invalid Hook call, Hooks can be called only inside of the body
component
I think is not possible to use hooks inside class component..
If it's not possible what is the best approach to fetch data from server inside this class ?
You cannot use hooks in a class component. Use componentDidMount instead.
Hooks can be used only in functional components.
You could rewrite your component to be a functional one like so:
export default Users = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch('exemple.com')
.then((response) => response.json())
.then((json) => setData(json.result)) // set returned values into the data state
.catch((error) => console.error(error))
}, []);
const renderUsers = () => {
return data.map((value, key) => {
// DO STUFF HERE
})
}
return (
<View style={{ flex: 1 }}>
{renderUsers()} //render results
</View>
)
}
I have an app where a user is prompted to enter a code, it calls an external service and returns data from the api. Currently I'm able to enter the code and call the api and get a response back, I can also poll it every 10 seconds and return the data (no sockets on api service).
I have two components, showLanding and showResult.
When the app initialises, I want to show showLanding, prompt for a code and return showResult.
The problem I'm having is I'm not able to get it to 'update' the view.
I have tried ReactDOM.render or render() within the getScreen function, I feel as though I've missed something glaringly obvious when reading the React Native doco.
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {showLanding: true, showResult: false}
}
render() {
if (this.state.showLanding) {
return (
<View
tapCode={this.state.tapCode}
style={styles.appContainer}>
{this.state.showLanding && <LandingComponent/>}
</View>
);
}
if (this.state.showResult) {
return (
<View
tapCode={this.state.tapCode}
style={styles.appContainer}>
{this.state.showResult && <ResultComponent/>}
</View>
);
}
}
}
export class LandingComponent extends React.Component {
getResult = (value) => {
this.state = {
tapCode: value.tapcode
}
console.log(this.state);
this.getScreen(this.state.tapCode);
}
getScreen = (tapcode) => {
setInterval(() => (
fetch('https://mywebservice.com/' + this.state.tapCode)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.then(this.state = {
showLanding: false,
showResult: true,
tapCode: tapcode,
resultResponse: this.responseJson
})
.catch((error) => {
console.error(error);
})
), 10000);
}
render() {
return (
<View style={styles.landingContainer}>
landing view, prompt for code
</View>
);
}
}
export class ResultComponent extends React.Component {
render() {
return (
<View style={styles.resultContainer}>
Show json output
</View>
);
}
}
There are plenty solutions, but you should definitely consider using a navigation library like react-navigation or react-native-router-flux to handle routing transitions between components.
My "dirty" suggestion would be: Let the App-Component render your Landing-Page and put the state property 'showResults' in there. Show the code-input if showResult is false, if not, show results.
export class LandingComponent extends React.Component {
constructor(props){
super(props);
this.state = {
showResults: false,
tapcode: null,
resultResponse
}
getResult = (value) => {
this.setState({tapCode: value.tapcode})
this.getScreen(this.state.tapCode);
}
getScreen = (tapcode) => {
setInterval(() => (
fetch('https://mywebservice.com/' + this.state.tapCode)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.then(function(res) {
this.setState({
showResult: true,
tapCode: tapcode,
resultResponse: res.json()})
return res;
})
.catch((error) => {
console.error(error);
})
), 10000);
}
render() {
return (
this.state.showResults ? <ResultComponent/> :
<View style={styles.landingContainer}>
call fetch here....
</View>
);
}
}
And please never mutate your state directly! Call setState() instead.
You need to move the API call up to App. Right now, showLanding is part of the App's state, but you're setting in the LandingComponent so you're not triggering a re-render.
Nothing is rendering on screen. No clue why its happening, No error anywhere. Wondering why nothing is showing on screen. Getting data from API properly. Code is given below:
import React, { Component } from 'react';
import { StyleSheet, ScrollView, TouchableOpacity, Text, View } from 'react-native';
import { Container, Content, Grid, Row, Col } from 'native-base';
import axios from 'axios';
import ItemCard from '../components/ItemCard';
export default class ItemHorizontalScreen extends Component {
constructor(props) {
super(props)
this.state = {
items: []
}
}
componentWillMount() {
axios.get('http://rallycoding.herokuapp.com/api/music_albums').then(response =>
this.setState({
items: response.data
}))
.catch((error) => {
console.error(error);
})
}
renderHorizontalContents() {
const rowItems = this.state.items
rowItems.map((rowItem, index) => {
return (
<TouchableOpacity key={index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}
render() {
return (
<View>
{this.renderHorizontalContents()}
</View>
)
}
}
Your renderHorizontalContents() should return the list:
renderHorizontalContents() {
const rowItems = this.state.items
return rowItems.map((rowItem, index) => {
return (
<TouchableOpacity key={index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}
Also, semi-related, as of React 16.3 React team advises not to use componentWillMount(). You should fetch the data in componentDidMount() LifeCycle hook.
More on componentWillMount() deprecation:
https://github.com/styled-components/styled-components/issues/1575
Try this. The issue is renderHorizontalContents() is not returning so you have to return elements which map returns for you
Also regarding adding key, if items array contains unique id per object then use that is as key that is recommended. Index is always second option if you don’t have unique id from data. Also when adding index as key you should add something like I did below instead of adding index as key directly.
renderHorizontalContents() {
const { items } = this.state;
return items.map((rowItem, index) => {
return (
<TouchableOpacity key={"Key"+index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}