0

I need to display random quote from API using React hooks useState and useEffect.

import React, { useState, useEffect } from "react";
const API =
 "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";
const App = () => {
  const [quote, setQuote] = useState({
    quotes: [],
    index: 0,
  });
  useEffect(() => {
    fetch(API)
      .then((res) => {
        return res.json();
      })
      .then((quote) => {
        setQuote(quote);
        console.log(quote.quotes[0].quote); // prints quote
        console.log(quote.index); // prints undefined
      });
  }, []);
  const getRandomIndex = () => {
    setQuote((previosState) => {
      return {
        ...previosState,
        index: Math.floor(Math.random() * quote.quotes.length),
      };
    });
  };
  return (
    <>
      <p>this is quote: "{quote.quotes[index]}"</p>
    </>
  );
};
export default App;

In the useEffect hook it prints correct quote, but it prints undefined for index. Could you help me to print random quote here

<p>this is quote: "{quote.quotes[index]}"</p>

after index was randomly generated.

2 Answers 2

1

you're going in the right way. Just some slight changes to make it work better.

  1. I separate quotes and index because the response is an object that has the "quotes" field, and not the index field. Your setQuote(quote); will set index to undefined.
  2. Each item in quotes is an object which has quote and author and if quotes is empty, [0] will be undefined, that's why I used optional chaining (?.) in quotes[index]?.quote.
import React, { useState, useEffect } from "react";
const API =
  "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";

const getRandomInRange = (min, max) => {
  return Math.floor(Math.random() * (max - min) + min);
};

const App = () => {
  const [quotes, setQuotes] = useState([]);
  const [index, setIndex] = useState(0);

  useEffect(() => {
    fetch(API)
      .then((res) => {
        return res.json();
      })
      .then((data) => {
        setQuotes(data.quotes);
      });
  }, []);

  const setRandomIndex = () => {
    setIndex(getRandomInRange(0, quotes.length));
  };

  return (
    <>
      <p>this is quote: {quotes[index]?.quote}</p>
      <button onClick={setRandomIndex}>Another</button>
    </>
  );
};
export default App;
Sign up to request clarification or add additional context in comments.

2 Comments

could you please explain me more detailed why you used ?. operator and how it works?
quotes[index].quote means you want to access quote from indexth of quotes. In case quotes = [] and index = 5, quotes[index] will be undefined and an error is thrown at quotes[index].quote. To avoid it, we must check if quotes[index] && quotes[index].quote. And quotes[index]?.quote is short-hand for the expression. More info here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
1

Hey I adjusted your quote state structure to be an array holding all the quotes that way you will not need to set random index, we can easily load a random quote based on array index. See the updated App.js here (I updated some of the namings and removed the getRandomIndex since that's redundant:

import React, { useState, useEffect } from "react";
const API =
  'https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json';
const App = () => {
  const [quotes, setQuotes] = useState([]);
  useEffect(() => {
    fetch(API)
      .then((res) => {
        return res.json();
      })
      .then((quote) => {
        setQuotes(quote.quotes);
      });
  }, []);

  return (
    <>
      {console.log(quotes)}
      <p>
        this is quote: "
        {quotes.length !== 0
          ? quotes[Math.floor(Math.random() * quotes.length)].quote
          : 'Loading'}
        "
      </p>
    </>
  );
};
export default App;

Also this line of code in your question logs undefined because quote references to the data coming from API and it does not have index property.

console.log(quote.index); // prints undefined because quote is from fetch and it does not have index property

3 Comments

it doesn't work, could you fix it
It should work I just did not add the import React, { useState, useEffect } from "react"; on the first line since it's the most basic thing and I thought you would know that. I updated the code in my response anyways, if you see error let me know what is the issue so I know what is wrong?
No problem at all :)

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.