I was able to retrieve random quotes from an API, and the quote objects appear as expected when I console.log() them inside the getNewQuote
method, but when I try to update the state with the quote, and click the button to display it, it doesn’t render the quote to the DOM at all. Please assist.
// Create the quote box component
class QuoteBox extends React.Component {
constructor(props) {
super(props)
// Create the state for the application
this.state = {
// To display the quote on the page
quote: {}
}
// To set the displayed quote to a randomly selected one from the array
this.getNewQuote = function() {
// Use AJAX to request a random quote from an API
req = new XMLHttpRequest();
req.open('GET', 'https://talaikis.com/api/quotes/random/', true);
req.send();
req.onload = function() {
// Update the state with the new quote object
quoteJson = JSON.parse(req.responseText);
this.setState(
{ quote: quoteJson }
);
};
};
};
render() {
return (
<main id='quote-box'>
<h1 id='heading'>Random Quote Generator</h1>
<section id='text'>{ this.state.quote.quote }</section>
<section id='author'>{ this.state.quote.author }</section>
<section id='source'>{ this.state.quote.cat }</section>
<section id='buttons'>
<a href="twitter.com/intent/tweet">
<button className='button' id='tweet-quote'>Tweet This!</button>
</a>
<button className='button' id="new-quote" onClick={ this.getNewQuote }>New Quote</button>
</section>
</main>
)
}
}
ReactDOM.render(<QuoteBox />, document.querySelector('body'));
OK, there are a couple of things going on here.
First, your getNewQuote function should not me declared inside the constructor. It should be a sibling to the constructor and render, preferably in between the two.
Next, the standard way of defining that function would be:
getNewQuote() {
Without this. We need this when referring to it later because we need it to know that it is a class method, but JS knows we are defining it as a class method because of where it is.
Next, you are going to run into a problem wth this.setState in your getNewQuote function because it will think you mean the this of that function and not the class. There are ways to bind this (and you should look them up) but for now we can use an arrow function (that don’t create a new this but inherit the old one.) So, I would define the method like this:
getNewQuote = () => {
But if you’d prefer, you can bind this - you can read about it here. Those will all come in handy eventually so learn them all.
Lastly, you’ll have a similar this problem with the callback function of your AJAX call. You could store this in a variable and pass it in, but the easier way is to again use an arrow function:
req.onload = () => {
When I make those changes, it works. Let us know if something isn’t clear.
1 Like
Thank you very much for your assistance; I will definitely read up on the proper usage of this
. However, now I have a new issue (it’s actually an old one, but I figured that I would get the app working, before addressing it). I added the freeCodeCamp testing script via the JavaScript settings, but the icon still doesn’t show up, so I can’t run any of the tests. I read another thread with this issue, and having the script added via the settings seemed to solve it for them, but it didn’t for me. Here’s my CSS:
body {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
background-color: #be9b7b;
}
#quote-box {
/* For the location of the element in its parent grid*/
grid-row: 2 / 3;
grid-column: 2/ 3;
/* For the grid items of this grid container */
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
justify-content: space-around;
align-items: center;
padding: 20px;
box-shadow: 5px 5px 1px 1px #854442;
background-color: #fff4e6;
border-radius: 5%;
}
/* CSS Selector for the quote box heading */
#heading {
grid-area: heading;
text-decoration: underline;
font-family: arial;
color: #3c2f2f;
}
/* CSS Selector for the text of each quote */
#text {
grid-area: quote;
font-style: italic;
font-size: 24px;
}
/* CSS Selector for the author of each quote */
#author {
grid-area: author;
font-size: 20px;
color: #4b3832;
font-weight: bold;
}
/* CSS Selector for the Tweet and New Quote buttons */
#buttons {
/* Put an even amount of space between the two buttons */
grid-area: buttons;
display: flex;
justify-content: space-around;
width: 100%;
}
/* Button class */
.button {
margin: 5px;
height: 10vh;
width: 20vh;
color: #4b3832;
background-color: #e6f1ff;
border-style: none;
font-weight: bold;
font-size: 3vh;
border-radius: 10%;
box-shadow: 5px 5px 1px 1px #9ac6ff;
}
/* CSS id's for the two buttons */
#tweet-quote {
}
#new-quote {
}
/* change orientation of buttons, when display is narrower */
@media (max-width: 800px) {
body {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
background-color: #be9b7b;
}
#quote-box {
/* For the location of the element in its parent grid*/
grid-row: 2 / 3;
grid-column: 2/ 3;
/* For the grid items of this grid container */
display: flex;
align-items: center;
flex-direction: column;
justify-items: center;
padding: 20px;
box-shadow: 5px 5px 1px 1px #854442;
background-color: #fff4e6;
border-radius: 5%;
}
/* CSS Selector for the quote box heading */
#heading {
grid-area: heading;
text-decoration: underline;
font-family: arial;
color: #3c2f2f;
}
/* CSS Selector for the text of each quote */
#text {
grid-area: quote;
font-style: italic;
font-size: 24px;
}
/* CSS Selector for the author of each quote */
#author {
grid-area: author;
font-size: 20px;
color: #4b3832;
font-weight: bold;
}
/* CSS Selector for the Tweet and New Quote buttons */
#buttons {
/* Put an even amount of space between the two buttons */
grid-area: buttons;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
width: 100%;
}
/* Button class */
.button {
margin: 5px;
height: 15vh;
width: 30vh;
color: #4b3832;
background-color: #e6f1ff;
border-style: none;
font-weight: bold;
font-size: 5vh;
border-radius: 10%;
box-shadow: 5px 5px 1px 1px #9ac6ff;
}
/* CSS id's for the two buttons */
#tweet-quote {
}
#new-quote {
}
}```
totally didn’t know that arrow functions inherit this
from their lexical scope. I thought it was merely syntactic sugar. Googling away now…
To help with the testing script, we would need to see your code. It should be a script
tag in your HTML.
I was able to get it working, by changing the CSS selector to operate on a class, rather than the body tag itself. Thanks for your help!