Tuesday, June 4, 2024
 Popular · Latest · Hot · Upcoming
61
rated 0 times [  64] [ 3]  / answers: 1 / hits: 54397  / 6 Years ago, fri, april 6, 2018, 12:00:00

I'm trying to write a component in React that will use the fetch() API to get data from a website, then use setState to set a state equal to the data, and then finally render the data. My code looks like this:



import React from 'react';

export default class Test extends React.Component {
constructor(props){
super(props);
this.state = {apiInfo: 'default'};
}

componentDidMount(){
fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(
function(response){
return response.json();
}
).then(function(jsonData){
return JSON.stringify(jsonData);
}
).then(function(jsonStr){
this.setState({apiInfo: jsonStr});
console.log(jsonStr);
});
}

render(){
return(
<tr>
<td>{this.state.apiInfo}</td>
</tr>
);
}
}


However, this results with an error saying I'm unable to setState of undefined. I end up rendering 'default' on my HTML. What exactly am I doing wrong here?


More From » reactjs

 Answers
78

Your error message is telling you exactly what the problem is:




unable to setState of undefined




So you're trying call setState as a method of an object that doesn't exist at that point. As a property of what object are you trying to call setState as a method?




this.setState({apiInfo: jsonStr});




Yes, it's your this that's the problem. At the point that you're trying to call it - i.e. inside a .then() of a fetch call - this is actually undefined. You can see this in the Chrome Devtools:



Chrome
I'm afraid that this is a slippery customer in JavaScript; its value can (and does) change depending upon the current context of your app.



There's several ways you can workaround this. One slightly clunky (but it works!) way is to capture your this value before you enter your .fetch() call, and assign it to another variable. You'll often see that or self variables used for this purpose, but they're just conventions. You can call the variable what you like.



Here's how I've reworked your componentDidMount() method capturing this to that, and calling that inside the .then():



componentDidMount() {
const that = this;
fetch(https://fcctop100.herokuapp.com/api/fccusers/top/recent)
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
return JSON.stringify(jsonData);
})
.then(function(jsonStr) {
that.setState({ apiInfo: jsonStr });
console.log(jsonStr);
});
}


If you're comfortable using arrow functions, then another way is to replace your normal function call with one, like so:



.then(jsonStr => {
this.setState({ apiInfo: jsonStr });
console.log(jsonStr);
});


An arrow function's this is always the this that its parent defined.


[#54750] Tuesday, April 3, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
joep

Total Points: 32
Total Questions: 97
Total Answers: 104

Location: Wales
Member since Thu, Jul 1, 2021
3 Years ago
joep questions
;