0

Been banging my ahead against a wall on this one for a while. Doing the FCC course, essentially completed a project but trying to fetch a JSON with an array rather than just putting one in directly, myself, as I wanted to learn how to do it... Didn't think it would be this difficult!

What do I want to do?

I want to fetch a json and assign the array within it to state within my react component. I'll then use a random num gen to pick a random quote to display from the array.

Where am I having trouble?

I'm able to fetch the json and log the quotes to the console, however whenever I try to assign them to a variable, I end up with the promise object. I think it's a problem that I must've misunderstood/not quite wrapped my head around asynchronous functions yet

What I need help with

I've created a new codepen, separate to the task, where I have been testing how to get this to work without React, so I can then work it into my React project when I know what to do.

I'm able to log the first quote in the array to the console when I run the async function, however when I try to use that same async function to return that quote to myQuote, it returns a Pending Promise. Am I approaching this correctly at all, or am I completely going in the wrong direction?

If you don't want to visit the codepen link, code below:

const testFetch = fetch('https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json')
    .then(response => response.json())
    .then((quote) => {
    return quote.quotes;
})

// The console.log below logs "The quote is [quote as a string]" to the console
const testVar = async () => {
    const quoteArr = await testFetch;
    console.log("The quote is ", quoteArr[0].quote);
    return quoteArr[0].quote;
};

let myQuote = testVar();

// This logs "Is my quote variable working? [Promise pending]" to the console
console.log("Is my quote variable working? + ", myQuote)
3
  • 1
    You didn't await you call to testVar(), I'm guessing that is why you're getting the Promise pending. Also, I'm confused as to why you would use the then() syntax together with the async/await syntax. Commented Oct 28, 2022 at 16:51
  • I did have a function that used testVar function that used .then() but I recall it giving the same result, this was another method I saw which just ended up the same as well. To use await on the testVar call, I would just do let myQuote = await testVar() , right? This seems to just result in "this is only allowed within async functions"? Commented Oct 28, 2022 at 16:59
  • Yes, you cannot await something that isn't in an async function, but think of it this way: The only thing "stoping your code at an instruction, waiting for it to finish" is the keyword await. Meaning when passing on let myQuote = testVar();, the code is not stoped and the console.log() is displayed immediately, regardless of the response of your API call. That is exactly why the console right after the await testFetch works, because you awaited the result before logging. Commented Oct 28, 2022 at 17:06

3 Answers 3

1

A common pattern in react (although not the best one) is to call fetch in useEffect and set the state in .then.

The simplest example would be

import React, { useEffect, useState } from "react";

const App = () => {
  const [quotes, setQuotes] = useState<any>([]);

  useEffect(() => {
    fetch(
      "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"
    )
      .then((response) => response.json())
      .then((quote) => {
        setQuotes(quote.quotes);
      });
  }, [setQuotes]);

  return (
    <div>
      {quotes.length > 0 && quotes.map((quote: any) => <div>{quote.quote}</div>)}
    </div>
  );
};
export default App;

A modern alternative in React is to use ReactQuery for fetching data, as it provides nice abstractions and caching out of the box.

Sign up to request clarification or add additional context in comments.

1 Comment

Helped progress, thank you. FCC's course is a bit outdated, I had to do research into 'useEffect', 'useState', etc... I'd been doing the constructor, super, state etc... The problem I'm having now: console.log(quotes), gives the array of objects... console.log(quotes[0].quote) gives undefined... console.log(quotes[0]) gives undefined... console.log(quotes["0"]) returns an object with quote key... console.log(quotes["0"].quote), throws an error. Wouldn't this essentially be the same method you used to map over the array? codepen.io/Jobeyobey/pen/WNyvKzB
1

In react, you need to load data after the render into the state. You can not just globally fetch and get data correctly. The below code will clarify.

const testFetch = fetch('https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json')
    .then(response => response.json())
    .then((quote) => {
    return quote.quotes;
})

const MyComponent = () => {
  useEffect(()=>{
     testFetch.then(quoteArr => {
      console.log('The quote is ', quoteArr[0].quote);
    });
  },[])
}

Comments

0

This syntax is equivalent to the async/await syntax in that it is resolving the promise. It's a redundancy using both.

const testFetch = fetch('https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json')
    .then(response => response.json())
    .then((quote) => {
    return quote.quotes;
})

You can try something like this

// you must also use react state to save your data
const [state, setState] = useState()

const testFetch = async () => {
  // with this syntax you need to wrap it in a try/catch to catch your errors
  try {
      // res here is equivalent to [response] above
      const res = await fetch('https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json')
      console.log(res)
      return res
    } catch (err) {
      console.log(err)
      return
    }
  }

// and called upon component mount using useeffect
useEffect(() => {
  const testVar = testFetch()
  setState(testVar)
}, [])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.