Reputation: 2289
I am using React-Native and am having issues just getting data to render from an API, into the render
function. I'm running node JS and express on one end to pull some data from a SQL database. This returns JSON that looks like this:
{"routines":[{"routine_id":1,"name":"Morning Routine","start_time":"2020-03-09T14:24:38.000Z","end_time":"2020-03-09T15:24:44.000Z","is_approved":0}]}
I want to loop through the routines
key and print out each routine
as components in React. I don't really care about what type of component that gets used, I just want to get the data. I've tried a few methods:
Method 1: Using componentDidMount
with fetch
:
constructor() {
super();
this.state = { routines: {} }
}
componentDidMount() {
fetch('http://localhost:3000/routines')
.then((response) => response.json())
.then((responseJson) => {
return responseJson;
})
.then( routines => {
this.setState({routines: routines});
})
.catch( error => {
console.error(error);
});
}
render() {
console.log(this.state)
render
of this.state
logs an empty object, despite the then(routines
portion of the code returning the correct data.
Method 2: Putting everything in componentDidMount
async componentDidMount() {
const response = await fetch("http://localhost:3000/routines")
const json = await response.json()
console.log('json');
console.log(json);
const routines = json.routines
this.setState({routines})
}
Again, logging the state in render
produces nothing while logging the json that gets returned from componentDidMount
does return valid data.
Inside the render
method i've also tried:
const { routines } = this.state;
And routines
comes up as undefined.
Method 3: Directly calling a function to set the state.
constructor() {
super();
this.state = { routines: this.fetchData() }
}
This ends up returning some weird data:
{"routines": {"_40": 0, "_55": null, "_65": 0, "_72": null}}
I'm assuming it's because react native does not want me to do this.
I just want a simple way to fetch data from an API and display that data in render
. I've gone through about four tutorials and all of them end up with undefined or objects set as the default value in the constructor in the render
method. Am I going crazy? It feels like this is somehow impossible..?
Upvotes: 1
Views: 2533
Reputation: 2900
its may be because fetch call is async ,and your render method may try to use it before its loaded by the api call, so your componentDidMount should be like
componentDidMount() {
this.setState({routines:null})
//fire an api call
fetch('http://localhost:3000/routines')
.then((response) => response.json())
.then((responseJson) => {
return responseJson;
})
.then( routines => {
this.setState({routines: routines});
})
.catch( error => {
console.error(error);
});
}
now inside your render function you should first confirm that routines is not null and have some valid values like
render(){
if(this.state.routines !==null){
//your code to render component
}else{
//your loading or error message
}
}
Upvotes: 0
Reputation: 33
You do everything right, just use state in render
and you will see updates.
constructor() {
super();
this.state = { routines: [] }
}
render() {
const { routines } = this.state
return (
<View>
{routines.map(item => <Text>{item.name}</Text>)}
</View>
)
}
Upvotes: 2
Reputation: 138
Since fetch is an async task the data this.setState({routines})
get's set after render()
is executed. You can execute this.forceUpdate()
after setting this.setState({routines})
. This will re-execute render()
when the data is set.
See: https://reactjs.org/docs/react-component.html#forceupdate
However, debugging mode can also be the culprit.
Upvotes: 0