ReactJS: Properties Of Object Become Undefined After OnClick Call
I've made a simple React app to display a number of image cards with quotes on them. It worked great, but then I refactored my code because I was getting a warning to use setState instead of directly altering the state properties. Then I started getting this error:
App.js:111 Uncaught TypeError: Cannot read property 'imageURL' of undefined
I guess this means that even if it was working before, I wasn't doing it properly. I suspect my problem is something to do with setState being asynchronous, but I'm having trouble finding a solution. Any light shed on the matter would be much appreciated!
Code below:
UPDATE:
Thanks for your suggestions! I have some updated code here, which is still returning the same error. Below are the up-to-date files as requested:
App.js: https://pastebin.com/daBTNKc7
App.css: https://pastebin.com/68xZdLfT
quotesData.json https://pastebin.com/1xD5DS0z
UPDATE 2:
I realised that I wasn't initialising this.state.cards in a sensible way, so the array was empty at a point when render() was trying to read it. I changed my constructor to initialise the array with some placeholder data, like this:
constructor(props) {
super(props);
this.state = {
imagesLoaded: false,
cards: [],
numItems: 6,
numLoaded: 0,
quotes: quoteData
};
for (var i = 0; i < this.state.numItems; i++) {
var quoteObject = ["Inspiring quote goes here.", "Speaker Name"];
var cardObject = {
imageURL: './src/placeholder.png',
quote: quoteObject[0],
credit: quoteObject[1]
};
this.state.cards.push(cardObject);
//Sleep between requests so Unsplash doesn't block us for overloading it.
this.sleep(500);
}
this.getRandomQuote = this.getRandomQuote.bind(this);
this.renderCard = this.renderCard.bind(this);
}
It's working now - thanks everyone for your assistance! It still needs improving but hopefully I can make it the rest of the way on my own.
Answer
You have several errors. The following are not all of them, but it is a good start :)
Fix these, post the updated code, post also quotesData.json
and App.css
, and we will continue...
Start by fixing the following:
You cannot setState from the constructor.
Add the following after the constructor (and remove the call to refreshImages
from the constructor).
componentDidMount() {
this.refreshImages();
}
'this' is not set properly in the following:
getRandomQuote();
renderCard();
Add the following inside your constructor:
this.getRandomQuote = this.getRandomQuote.bind(this);
this.renderCard = this.renderCard.bind(this);
After your updates, you are almost there :)
The problem that remains is that, although you set the cards value in the right place (componentDidMount
), setState is asynchronous, so the first time you enter render()
, cards are still not set.
I replaced the following line:
if (this.state.imagesLoaded) {
With the following:
if (this.state.cards.length === 0) {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">state.images still empty</h1>
</header>
</div>
);
} else if (this.state.imagesLoaded) {
And I see smart quotes with nice images :)
This is a workaround, of course, you need to decide what to do... Also, is sleep(500) in refreshImages really needed?
One more advice (not related to the problems you are having): use reactstrap, it will make your life easier. You need to know bootstrap for that, which is very easy to learn (but don't use bootstrap, use reactstrap).
Good luck with your work :)
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?