Reputation: 308
I am trying to render a component that gets the data from Django rest framework using the fetch() call. I have to use fetch twice because of the way my data is structured.
When I am trying to setState after I receive the data and pass it to a component and console.log it, I get empty braces {} and when I expand it I have data but I am not able to access it. But if I expand it I can see the data
example: {} Hotel: 123, Office: 456
data.Hotel = undefined
normally when I console.log a data it looks something like {Hotel:123, Office:456}
Is the way I have structured react wrong or am I missing something? I am new to react so any help would be appreciated.
DataProvider.js
import React, { Component } from "react";
import PropTypes from "prop-types";
class DataProvider extends Component {
static propTypes = {
endpoint: PropTypes.string.isRequired,
};
state = {
project: {},
run_set: [],
project_eui: 0,
run_euis: {},
loaded: false,
placeholder: "Loading.."
};
componentDidMount() {
let currentComponent = this;
var project = {}
var run_set = {}
var project_eui = 0
var run_euis = {}
var run_sets = []
try {
const data = {username: 'username', password: 'password'};
fetch('URL', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
}).then(function(response) {
return response.json();
}).then(function(data){
return data.token
}).then(function(token){
try {
fetch(currentComponent.props.endpoint, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': 'Token ' + token
}
}).then(function(response) {
return response.json();
}).then(function(project){
project = project
project_eui = project.eui
var numBuildingType = project.run_set.length
for (let i = 0; i < numBuildingType; i++) {
try {
//URL from 1st fetch call
fetch(project.run_set[i], {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': 'Token ' + token
}
}).then(function(response) {
return response.json();
}).then(function(run_set){
run_sets.push(run_set)
run_euis[run_set.building_type] = run_set.eui
})
} catch (e) {
console.log(e);
}
}
})
} catch (e) {
console.log(e);
}
})
} catch (e) {
console.log(e);
}
currentComponent.setState({ project: project, project_eui: project_eui, run_set: run_sets, run_euis: run_euis, loaded: true });
}
render() {
const { project, project_eui, run_set, run_euis, loaded, placeholder } = this.state
if (loaded == true) {
const myJson = { "project": this.state.project, "run_set": this.state.run_set, "project_eui": this.state.project_eui, "run_euis": this.state.run_euis}
return this.props.render(myJson)
} else {
return <p> {placeholder} </p>
}
}
}
StructureData.js
...
const StructureData = ({ data }) => {
console.log(data.run_euis) --------------------> {}
return (
<div>
<p>something</p>
</div>
);
}
export default StructureData;
App.js
...
return <DataProvider endpoint= {projectApiEndpoint}
render= {data => <StructureData data={data} />}
/>
...
Upvotes: 0
Views: 46
Reputation: 11581
currentComponent.setState({ project: project, project_eui: project_eui, run_set: run_sets, run_euis: run_euis, loaded: true });
is in the wrong place.
You start a very complicated asynchronous Promise chain which involves a fetch
. That code will take some time to complete. You can't use setState
synchronously immediately after, because your fetch
code is still in-flight. Your setState
call needs to be inside of your fetch
's successful resulting .then
, maybe here?
//URL from 1st fetch call
fetch(project.run_set[i], {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': 'Token ' + token
}
}).then(function(response) {
return response.json();
}).then(function(run_set){
run_sets.push(run_set)
run_euis[run_set.building_type] = run_set.eui
currentComponent.setState({ project: project, project_eui: project_eui, run_set: run_sets, run_euis: run_euis, loaded: true });
})
The behavior you're seeing in console is due to the fact that when you log an object to the console, what you see is its value at the moment that it was logged. In this case you create an object variable, start a fetch
call, and then log the object - but at that moment the object is still empty. However, by the time you click the "expand" arrow in the console, it will re-evaluate the object and show you its new current value - which happens to be after the fetch
has completed. Using console.log
for debugging can be prone to weird behavior like that; I recommend you get used to using the debugger tools. https://medium.freecodecamp.org/mutating-objects-what-will-be-logged-in-the-console-ffb24e241e07
Upvotes: 1