I am creating a random quote generator. Everything works fine. But the quote doesn't appear at the page reload. I have to click new quote button to get a new quote. It should also display a quote when the DOM is loaded.
My Code:
import { useCallback, useEffect, useState } from 'react';
import './App.css';
function App() {
const quotesURL ='https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json';
const [quotes, setQuotes] = useState([]);
const [randomQuote, setRandomQuote] = useState('');
const fetchQuotes = useCallback(() => {
fetch(quotesURL)
.then(response => response.json())
.then(data => setQuotes(data.quotes))
.catch(err => console.error(err));
// console.log(quotes);
}, [quotesURL]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleNewQuote = () => {
const randomIndex = Math.floor(Math.random() * quotes.length);
setRandomQuote(quotes[randomIndex]);
};
useEffect(() => {
fetchQuotes();
}, []);
return (
<div>
<div id='quote-box'>
<div id='text'>{randomQuote.quote}</div>
<div id='author'>{randomQuote.author}</div>
<button id='new-quote' onClick={handleNewQuote}>
New Quote
</button>
<a href='https://www.twitter.com/intent/tweet' id='tweet-quote'>
Tweet Quote
</a>
</div>
{quotes?.map((quote, index) => (
<div key={index}>{JSON.stringify(quote)}</div>
))}
</div>
);
}
export default App;
What I want is to display a quote at the reload of the page. It currently works only when the button is clicked!
The problem according to my understanding is that the useEffect calls fetchQuotes()
after handleNewQuote()
, so there is no quote to load
CodePudding user response:
Try including the following in your component:
useEffect(() => {
if (!randomQuote) {
const randomIndex = Math.floor(Math.random() * quotes.length);
setRandomQuote(quotes[randomIndex]);
}
}, [quotes]);
This runs when the quotes have been loaded and but random quote is still null.
Or even better, call setRandomQuote()
at the time you fetch quotes.
const fetchQuotes = useCallback(() => {
fetch(quotesURL)
.then(response => response.json())
.then(data => {
const randomIndex = Math.floor(Math.random() * data.quotes.length);
setRandomQuote(data.quotes[randomIndex]);
setQuotes(data.quotes)
})
.catch(err => console.error(err));
}, [quotesURL]);
CodePudding user response:
There's a lot of ways to do it, but I think the best one would be to set random quote when the data is loaded. It can be done after fetch or in useEffect
So I'd do following
const handleNewQuote = useCallback(() => {
const randomIndex = Math.floor(Math.random() * quotes.length);
setRandomQuote(quotes[randomIndex]);
}, [quotes, setRandomQuote])
// useCallback so it can be passed to useEffect safely without infinite loop (memoize function when component rerenders)
useEffect(() => {
handleNewQuote()
}, [quotes, handleNewQuote])