Help fetching JSON for random quote machine project

Here is my project so far: https://codepen.io/dialectrical/pen/eYzgypR?editors=0011

I am at my wits end with this project and cannot find an adequate solution that both does what I need it to do and actually makes sense to my level of skill.

I would like to know how to fetch a JSON file and store it in a variable, quotes or something similar such that I can access it as one might access an array or imported file.

The common approach of

fetch('./data.json') .then((response) => { return response.json() }) .then((data) => { // Work with JSON data here console.log(data) }) .catch((err) => { // Do something for an error here })

Does not seem to let me do this, as I can only manipulate the data within the fetch request and cannot pass data within it to other variables or object properties. In short, I would like quote and author to receive a corresponding quote and author from a fetched JSON file. This works fine in my code with an imported JSON or a hardcoded object, but, again, I cannot find an adequate explanation of how fetch works in order to implement a solution on my own.

@dialectrical You have not defined a variable named quotes anywhere in your code, but you are trying to reference it on line 32.

quotes is a placeholder variable for where I would like the JSON data to go.
I have the code working locally by importing my JSON data to a quotes variable. I would like to fetch the JSON data to the quotes variable.

In your render method of the App class, you reference <Quote />. Why not pass the component’s state property quoteData as a prop to <Quote /> and then you can access that property’s value to use however you want. You really do not even need the Quote component to hold any state properties as you can just reference this.props and the applicable properties passed to it.

My question is specifically about how I can use fetch() to accomplish this. I am not asking for help optimizing or cleaning up my code. I just want to know how to use fetch() to take the JSON data and put it in a variable.

The above explains how to use fetch. However, you are going to need to rethink your code a bit, because you can not just assign the results to a variable and expect it to work. You need to assign the results to a state property since based on how you currently are attempting to structure your app. The fetch method is asynchronous, so if you attempted to assign some global variable the results, if you attempted to display the value by referencing the global variable before the fetch completed, you will end up with undefined for the results.

Yes I am aware of all this. My question is how to accomplish this, as I cannot find anything at my level of comprehension that explains to me how to overcome the issues with fetch being asynchronous, as everything I have tried and searched for has failed and returned undefined.

EDIT: my quote engine Pen has been updated with an attempt at setting the state of App with the fetched data, but it still appears to not be working.

I explained what I recommended you to do in my first 2nd reply. See if you can implement what I said. If you do not understand something I stated, do not hesitate to ask. I will try to explain it in a different way.

I see you have passed a prop named quotes to your Quote component. This is fine, but in your Quote component, you would need to reference the prop via this.props.

EDIT: I must have been looking at a different version. I see you do have this.props. Let me look at your code a bit more and I will reply back.

I have–it’s possible it’s slow to update? At any rate, console.log(this.props.quotes) within Quote returns an empty array, suggesting the fetch() data is not properly being sent to quoteData in App.

EDIT: sure, no worries. Thanks for taking the time to look through it.

As far as additional testing goes, the fetch() statement appears to be getting everything correctly–
.then(data => console.log(data)) will log the object correctly to console.

However, .then(data => this.setState({quoteData: data}) seems to fumble and the data disappears into the ether.

I checked your code and fixed it. Though I want you to fix it by your own so I will drop a hint. Check your fetch method where you convert the response to json using response.json(). Now, you set the quotes to a state variable quotesData which is where you are making a mistake. Try to console the data first and then assign it to any variable.

Here is the correct fetch method which will update the state with fetched data. Check it once you have tried around to fix your code and still failed.

fetch(‘https://gist.githubusercontent.com/dialectrical/f1354d9dd1bfb81216cbf498717f3c34/raw/462fecc8e3e67063ddebb01a0fd2a1b8946713ec/civ-quotes.json’)
.then(response => response.json())
.then(data => this.setState({quoteData: data}))
.then(() => console.log(quoteData));
}

It’s possible you’ve loaded into an older version of the Pen I posted, but I believe I have that exact same chunk of code in my code, and it is not working.

In the React pen, the console.log(quoteData) is logging a blank array (or whatever else I initialize quoteData as. However, in this example code, you can see console.log(obj) within the fetch() chunk logging the correct data to console. However, you can also see console.log("var outside of fetch: " + obj) logging undefined.

thats because fetch is asynchronous, based on your pen, it creates a variable named obj in memory, then calls the fetch method, now it processes the fetch method and moves on to next line where it logs the var obj which is still undefined. So the value of obj outside of fetch is first undefined and then changes to the data.

Yes, I am aware that the fetch() issue pen has this issue. However, it logs the data correctly, unlike the FCC: Quote engine pen which has near identical code.

The code you provided in your solution is exactly the same as what was already in my code. Would you be able to weigh in on that a bit more closely?

sure i can, just provide me updated codepen link

Ok so there are minor issues with the code which i fixed and now your code is up and running.

function tweetButton(props) {
return(

tweet

);
}

function Button(props) {
return(
<button id=“new-quote”
onClick={() => props.onClick()}
>
New Quote

);
}

//Parent of Button, Child of App
class Quote extends React.Component {
state= {
quote: ‘’/.quotes[rand].quote/,
author: “-” + ‘’/.quotes[rand].quote/,
}

getRandomInt = () => {
const max = this.props.quoteData.length;
return Math.floor(Math.random() * (max));
}

handleClick = () => {
const rand = this.getRandomInt();
this.setState({
quote: this.props.quoteData[rand].quote,
author: “-” + this.props.quoteData[rand].author,
});
}

render () {
return (



{this.state.quote}


{this.state.author}





);
}
}

//Parent
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
quoteData: ,
num: 92,
}
}

async componentDidMount() {
const url = “https://gist.githubusercontent.com/dialectrical/f1354d9dd1bfb81216cbf498717f3c34/raw/462fecc8e3e67063ddebb01a0fd2a1b8946713ec/civ-quotes.json”;
const response = await fetch(url);
const data = await response.json();
this.setState({ quoteData: data.quotes, loading: false });
}

render() {
if (this.state.loading) {
return

loading…
;
}
return (
  <div className="quoteEngine">
    <div className="quote">
      <Quote quoteData={this.state.quoteData} />
    </div>
  </div>
);

}
}

ReactDOM.render(, document.getElementById(“root”));

Thanks–I was able to cobble together a solution shortly before you posted this but I will keep this in mind if I ever revise the code.