Calling another function in a function in a React component

I am building the random quote machine and I was using this code:

constructor(props) {
    super(props);
    this.state = {
      quote: "Loading...",
      author: "",
      quotes: [],
      index: 0,
    };
    this.newQuote = this.newQuote.bind(this);
  }
  componentDidMount() {
    fetch(
      "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"
    )
      .then((res) => res.json())
      .then((data) => {
        this.setState({
          quotes: data.quotes,
        });
      });
    this.newQuote(); //<--This throws an error
  }
  newQuote() {
    this.setState({
      index: Math.round(this.state.quotes.length * Math.random()),
      quote: this.state.quotes[this.state.index].quote,
      author: this.state.quotes[this.state.index].author,
    });
  }

which throws this error:

TypeError: this.state.quotes[this.state.index] is undefined

I somehow accidentally realized that if I put the call to my newQuote function inside my fetch function then everything works perfectly.

constructor(props) {
    super(props);
    this.state = {
      quote: "Loading...",
      author: "",
      quotes: [],
      index: 0,
    };
    this.newQuote = this.newQuote.bind(this);
  }
  componentDidMount() {
    fetch(
      "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"
    )
      .then((res) => res.json())
      .then((data) => {
        this.setState({
          quotes: data.quotes,
        });
        this.newQuote();  //<--This works
      });
  }
  newQuote() {
    this.setState({
      index: Math.round(this.state.quotes.length * Math.random()),
      quote: this.state.quotes[this.state.index].quote,
      author: this.state.quotes[this.state.index].author,
    });
  }

Can anyone tell me why this happens?

That’s because in the second case you invoke the function at the bottom of the .then chain, when the gist data are loaded^^
In the first case you call it outside of the chain: basically the data fetching starts and right after your function will be invoked, while data are still loading^^

EDIT:
Oh, welcome to the forum btw :grinning:

1 Like

Ahh, asynchronous stuff! So I think it is better to specifically put the second function inside another .then then. I think it doesn’t make any difference but this way my function doesn’t look so homeless. :smiley:

    fetch(
      "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"
    )
      .then((res) => res.json())
      .then((data) => {
        this.setState({
          quotes: data.quotes,
        });
      })
      .then(() => {
        this.newQuote();
      });
  }

P.s. Thank you!

1 Like