Hey there,
Let me tell you today regarding how not to program infinite loop in reactjs.
Finding
Yesterday I was trying to make a Reddit clone in ReactJS with a database from firebase firestore. I made the structure of the app where the inputs were taking the data and outputs were showing a user's post.
The problem happened when I tried to add some posts and tried to upvote or downvote those posts. After some minutes I see a page saying,
Firebase Error, Quota exceeded
I canceled it and refresh the page to see if it magically disappears, However, I was wrong, It didn't and I had to spend and full day and a lot of help/discussion from #TeamTanay community. I was constantly getting this error,
I checked the firebase console out of curiosity and I was over 50,000 reads in less than 4 hours.
Reaching out
I reached out to #TeamTanay community with my problems and link to this code sandbox URL. Members of the community offered different solutions to me.
I think it's because of the logic that you have in your
useData
component — you're reading the entire collection every timetimes
changes.if you read the fine print in the quota limits in firebase, you should see that this is what is leading to it
Suggestions
One user said.
this, and you are calling firebase read every time the page renders... so for 50k reads, assuming you have 10 posts, you'd only need like 100 or so refreshes in a day to cross the quota...
Don't do that.
optimize using memoization first. I am not sure, but probably useMemo after reading upon them. the firebase read should only work periodically, or when you write something new.
another one said.
At this point, My useData
function was looking like this,
function UseData() {
const [times, setTimes] = useState([]);
useEffect(() => {
var citiesRef = firebase.firestore().collection("times");
// Create a query against the collection.
// var query = citiesRef.where("uid", "==", uid);
citiesRef.get().then((snapshot) => {
const newTimes = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setTimes(newTimes);
});
}, [times]);
return times;
}
Discovery
After this communication, I was sure that my page making much more rerendering than I need in reality. My first thought was to get for useEffect
, but I was not sure how it was causing this error. I did everything right(Narrator: he didn't) and rerendering only when update in the database, It was only when another person suggested me,
No, useEffect that you have created in the useData function is called every time "times" is updated. But you update "times" in useEffect itself which leads to useEffect being called infinitely. (You can use console.log() to check this)
Pass [ ] instead of [times] as the second argument in that useEffect then it will work properly.
Solution
I looked at the function again and discovered that I was making an infinite loop between the useEffect
and Times
state. I was calling the useData
function to retrieve and update the data. So whenever I was doing that, I was invoking the useEffect
function and Due to that, Times
was getting updated. And I have passed Times
in useEffect
rerender array, So whenever times
was getting updated, invoking useEffect
again. And It was going in a loop until firebase stops it by giving an error.
Key Takeaways
- Always check and understand what you are passing in useEffect(or any function in general)
- Google won't be able to find your answers, reach out to the community.
- Ask questions multiple times, if unanswered once.
- Listen to people's feedback and improve that mistake next time.
A Nice ending with dev joke for you,
Ques: What is the problem with git jokes?
Answer: Everyone has their own version!