Infinite loop inside useEffect while trying to use Firebase - reactjs

I'm building an app to write down values for electrical and gas meter : https://n3g.gitlab.io/react-conso-energie/
If you check the console, you'll see an infinite print of a console.log.
Here's the file where this magic happen :
https://gitlab.com/n3g/react-conso-energie/-/blob/br/V2/src/ListingExpansionPanels.js
I don't understand why my useEffet (line 19) is fired infinitely although I've add [dbRef] check at line 36..
In my imagination, it would be fired only if I add or remove things in my database ?
Thanks you if someone can take a look because I'm struggeling with this since few weeks. I do believe I'm over complicate things when I try to fecth data from my database..

Try wrapping firebase.database().ref('2020') with useRef hook like this:
const dbRef = useRef(firebase.database().ref('2020'));
And remove dbRef from useEffect deps array, change usage from dbRef to dbRef.current

Related

useEffect() in my search Bar component causes an infinite loop, that I cannot understand

I'm new to React-Native and am following along in a course on react-native.
This git hub links to a my repository the code has the problem(infinite loop) I describe in the following question.
I have spent 12+ hours trying to figure this out. Please help me figure this out if you can.
https://github.com/JohnyClash/mealsToGo
useEffect in question
above photo directory: 'src/features/restaurants/components/search.components.js'
useEffect(() => {
search(searchKeyword);
}, []);
The above code creates a feedback loop that causes the app to continuously fetch from a mock api, that returns the location information, loads to the screen and then quickly reloads ad infinitum.Its intended purpose is to run a single time on component mount to cause a single default search. Instead, This useEffect() inside of search.component runs its callback repeatedly. The useEffect is not tracking a dependency that has changed, and is given [] an empty array in place of dependency
useEffect(callback,dependencies)
useEffect(callback,[])
Shouldn't this syntax of useEffect only run once after its mount, and not run again if something is updated? If my understanding is correct how is it possible that this use effect is running in an infinite loop?
this useEffect() is the culprit as the infinite reload loop stops when it is this useEffect() is removed.
all other functionality down this logic chain does not create an infinite loop, as in the search method initiated through onSubmitEditing works well without looping.
The problem of this infinite loop is being caused by this location object here, probably because every time the LocationContext is rerendered (a search is done or state is updated), it creates a new instance of the location object, which makes the useEffect be called again, then it search again, recreates the location object when calling useEffect again, which makes a new search, update some state and recreates the location object...
Code with problem of infinite loop:
useEffect(() => {
console.log(location)
if (location) {
const locationString = `${location.lat},${location.lng}`;
retrieveRestaurants(locationString);
}
}, [location]);
If you do something like this, might solve this problem:
useEffect(() => {
if (location?.lat && location?.lng) {
const locationString = `${location.lat},${location.lng}`;
retrieveRestaurants(locationString);
}
}, [location?.lat, location?.lng]);
Also be careful with setTimeout, and not clearing it on component unmount
Tip: Always avoid object, array or function in useEffect dependency, and if necessary it needs to be memorized with useMemo or useCallback
Try This :
useEffect(() => {
search(keyword)
}, [keyword])

React updating State from Firebase Server

I have a firebase database, that has a collection called "post" and in post there 6 variables (displayName, userName, verified, text, image, avatar). The idea is, there will be multiple posts in the database.
React Code:
const [posts, setPosts] = useState([]);
//Whenever the firebase database changes, it runs this method
useEffect(() => {
db.collection("posts").onSnapshot((snapshot) =>
//Loops through all the posts and adds the data into an array
setPosts(snapshot.docs.map((doc) => doc.data()))
);
}, []);
In react, I have two state variables, posts and setPosts. I'm assuming they are initially just set to empty arrays.
Now I have the useEffect function, that I am told runs whenever the database changes/updated. First question, how does the function know that the database updated? In other words, how does the useEffect function work?
Secondly, I'm pretty sure in the end, the post variable becomes a list of all the post objects in the database. I'm not sure how that happened. I have attached the code that updates this state above, but I'm not too sure how it works. Can you please break it down and explain how it works? I'm also not sure what the setPosts state is used for.
Please let me know!
In the above
In line 1 - You have used State hooks to set up posts as an empty Array. More reading can be done here to understand what state hooks mean - https://reactjs.org/docs/hooks-state.html
Next you set up a useEffect hook function (https://reactjs.org/docs/hooks-effect.html) to make a backend (firebase) api call after rendering.
Inside the hook function you are looking up data from the posts collection in firebase and bringing back a snapshot of all the documents in that collection. db.collection("posts").onSnapshot(callBack). The callback function is called every time something changes on the underlying database using well known observer pattern (read more in following links https://rxjs-dev.firebaseapp.com/guide/overview, https://firebase.google.com/docs/reference/node/firebase.firestore.CollectionReference#onsnapshot)
Then in the onSnapshot callback function you get an array containing documents which is further mapped to an output array using the javascript Map function snapshot.docs.map((doc) => doc.data()). https://www.w3schools.com/jsref/jsref_map.asp
Finally this output array is set in the posts variable using the
setPosts() method.
Hope this breakdown helps and I suggest reading the links in detail so its clear how everything comes together.

useState doesn't run correctly in websocket connection

Hello guys I had a problem. I don't know it is a bug or not but I think it is a bug. I would open an issue on github repo of react but first I wanted to look at here and ask to you. I will give you all my code on the bottom of this post
What is the problem?
I am connection a socket when my component first mounted and catched the user to connect live chat. And I use useState to set messages when I or agent send a messsage on message event. I use useState on the line of 114. First of all this useState(setMessages on ) works correctly. But If I set the setMessages by the other ways this won't work.
For Example 1:
If I set this setMessages like below, setMessages works correctly and changes state but messages state not rendering on DOM correctly. I didn't udnerstand what's wrong.
const dummy = [...messages]
dummy.push(data.messageData)
setMessages(dummy)
For Example 2:
If I set this setMessages like below, setMessages doesn't work and I got an error and I never see my rendered page because it say ...prev is a null. I didn't understand what's wrong again.
setMessages((prev) => [...prev, data.messageData])
For Example 3:
This is the most interesting part of my code. It's really impossible one. If I remove line 111 and 112 (those are below here) the version of runs correctly of my codes doesn't work and setMessages doesnt work by the way with concat either. And I don't use those codes anywhere you can see that by using Ctrl+F. I just described those to set setMessages with the dummy variable but that didn't work and now I can't delete them because if I delete them my working codes won't work either.
const dummy = messages
dummy.push(data.messageData)
Now guys what's wrong on there. I fight all day with this buy I didnt find any reason. Is it a bug or not? Have a good days I will be here for your replies.
This is all of my codes in the page that I have a problem
https://gist.github.com/mucahidyazar/5ccff6d67d95d23dfb470dfe026f714b
You are using the useState incorrectly and its not a problem with react ;)
You need to create a new object reference if you use setState.
For example a string, number or boolean are always new instances.
But this does not work for objects. Push keeps the old object reference and setting a value to the same reference as before to the useState hook will be skipped.
const dummy = messages
dummy.push(data.messageData)
setMessages(dummy)
You are passing he same object to the setState (here setMessages) than before (push only adds the item to the same obejct), but you need a new instance instead, or else react will not rerender.
setMessages((prev) => [...prev, data.messageData])
but this only works if the default item is an array, so make sure you are setting ... = useState([]) so that prev is defined.
For line 111, yes the current object receives the new items, so the console.log shows the correct data,but since its the same instance (push does not create a new instance of the array), the rerender gets skipped and you will not see any changes on the resulting website.
o when I take a look at your code, change this:
const dummy = messages
dummy.push(data.messageData)
console.log(dummy)
setMessages(messages.concat(data.messageData).slice(0, messages.length)
to
setMessages([...messages, data.messageData])

react leaflet onMoveEnd cause error : "Maximum update depth exceeded"

I have the following code to perform a state update every time the map move.
function updateMap() {
const b = mapRef.current.leafletElement.getBounds()
const zoomm = mapRef.current.leafletElement.getZoom()
const initBound = [b.getSouthWest().lng, b.getSouthWest().lat, b.getNorthEast().lng, b.getNorthEast().lat]
setZoom(zoomm)
setBound(initBound)
}
bellow is the Map Component, I also tried the onMoveEnd event
<Map onViewportChanged={updateMap}/>
it is working fine for couple of moves however sometime especially if I kept moving the map it freezes and I get the Maximum update depth exceeded error .
can someone please explain the reason, is it a bug on react Leaflet or am I doing something wrong?
You get that error because you're updating state on every move, and in react you can update the state just for a limited number of times to prevent infinite loops for example.
One way to solve the problem is to debounce the updateMap method.
Check this link to look at different ways of performing the debouncing.
I hope this helps!

React, ESLint: eslint-plugin-react-hooks shows incorrect "missing dependency"

Assume you are using React and you are writing a custom hook useSomething that returns the identical same thing each time it is invoked for the same component.
const something = useSomething()
// useSomething() at time X === useSomething() at time Y
If you now use this something value inside of a useEffect(() => ...) and you do not pass something as a dependency to the array of the second argument of useEffect then the linter will warn you:
React Hook useEffect has a missing dependency: 'something'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
Of course ESLint cannot know that something will always stay identical (per component), but adding not-changing things like something to the dependency array of useEffect each time they are used is really annoying. Just deactivating react-hooks/exhaustive-deps does also not seem to be a good solution (nor using // eslint-disable-next-line react-hooks/exhaustive-deps).
Is there a better solution than to add things like that unnecessarily to the dependency array of useEffect just to make the Linter happy?
Please find a simple demo here:
https://codesandbox.io/s/sad-kowalevski-yfxcn [Edit: Please be aware that the problem is about the general pattern described above and not about this stupid little demo - the purpose of this demo is just to show the ESLint warning, nothing else]
[Edit] Please find an additional demo here:
https://codesandbox.io/s/vibrant-tree-0cyn1
Here
https://github.com/facebook/react/issues/14920#issuecomment-471070149
for example you can read this:
If it truly is constant then specifying it in deps doesn't hurt. Such as the case where a setState function inside a custom Hook gets returned to your component, and then you call it from an effect. The lint rule isn't smart enough to understand indirection like this. But on the other hand, anyone can wrap that callback later before returning, and possibly reference another prop or state inside it. Then it won’t be constant! And if you fail to handle those changes, you’ll have nasty stale prop/state bugs. So specifying it is a better default.
So maybe just adding that never-changing values to the dependency array of useEffect may yet be the best solution. Nevertheless I hoped there would be something like a ESLint react-hooks configuration possibility to define a list of hook names which whose return values should be considered as static.
The example is a little contrived but I suspect you may wish to create a new useEffect block without this dependency.
If the store is not changing though I'd question why you'd wish to console log it time. If you wish to log it only on change then you'd add someStore to your dependency array. It really depends on what you're trying to achieve and your seperation of concerns.
I'd argue that if someStore is used as part of whatever logic is handled in this effect then it does belong in your dependency array.
You could also alternatively move const something = useSomething() into your effect and extract it as a custom hook link
useEffect(() => {
console.log("Current state (may change)", someState);
}, [someState]);
useEffect(() => {
console.log("Current store (will never change)", someStore);
});

Resources