First, I will say that I am quite new to react.
I am fetching data from firebase and randomly changing the data on the screen in setInterval. There are some things going on that I do not understand, so I would like to ask about them.
I have doubts about the working principle of the interval and
useEffect. Inside the useEffect there is no dependency souseEffectexecutes only for the first time. How does function inside the interval works after every some second, whenuseEffectonly works for once? I think interval function is inside theuseEffect,useEffectshould execute in order to run interval function.When I set the time to 1000 inside
setInterval, react sayscurrent_quotestate is undefined, but everything is fine when I set it to 2000 or over. Why?Return callback function of useEffect . I know it runs everytime right before the next render, to clean the interval of the previous render,but when I console something inside return why it does not execute?
import db from '../components/db'
import {useState,useEffect} from 'react'
const Home = ()=>{
const [current_quote,set_current_quote] = useState({});
const [isloaded, set_loaded]= useState(false)
let arr_data=[];
useEffect(()=>{
// fetching data from database
db.collection("data").get().then((querySnapshot) => {
querySnapshot.forEach(element => {
var data = element.data();
arr_data.push(data);
})
})
const interval = setInterval(()=>{ // randomly changing state
set_current_quote(arr_data[Math.floor(Math.random()*(arr_data.length))])
set_loaded(true);
},1000)
return ()=>{
clearInterval(interval)
}
},[])
return (
<div>
<h1>{ isloaded && current_quote.Quote} </h1> // displaying random data
<h4>{ isloaded && current_quote.Author}</h4>
</div>
)}
export default Home;
CodePudding user response:
Hope this moves your understanding forward:
useEffect runs once, reads from the database once, and sets the interval function once. The javascript engine will call the interval function you set ever interval milliseconds until you
clearInterval()it. The code is OK. Inside the interval method, you're calling a method set_current_quote() that you received from React's useState() hook. That will dirty the component and cause it to re-render.the 1st time your code runs, current_quote = {}, so
current_quote.Quoteis undefined. However, while current_quote is undefined,isloadedshould be false - so at a glance I'm not sure why you're getting the undefined error.The useEffect return callback is called when the component is torn down. If you remove the compoent from the dom (e.g. by navigating away) you'll see it gets called.
You can move arr_data to inside useEffect. It's not used outside that scope and it's not saved across renders (no const [arr, setArr] = useState()).
// instead of this...
let arr_data = []
querySnapshot.forEach(element => {
var data = element.data();
arr_data.push(data);
})
// you can do this...
let arr_data = querySnapshot.map(element => element.data())
