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

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!

Related

When swiping react native app - screens shows twice

Live example https://snack.expo.dev/su1-U5DZc
If I swipe screens with buttons - everything okay, but if I swipe with gesture - screens shows twice. Why so? Does this setWtf(state.index);
const onTouchStart = (e, state, context) => {
console.log('onTouchStart: ' + state.index);
setWtf(state.index);
};
make index stored somewhere by reference and then get updated?
Yes it was due to setWtf(state.index);. There is a reported bug of render issue when updating state in their official git page.
They are saying to downgrade react-native-swiper to version 1.5.5
or you could follow other solutions mentioned here : Update the state breaks the slides
Without more information, it's impossible to pinpoint the exact cause of the problem you're experiencing, although it's conceivable that the problem is connected to the way your code handles touch events.
Your code is probably adjusting the value of state.index depending on the gesture when you swipe between screens, and then refreshing the screen display based on the value of state.index. The screen display may update twice if state.index is being updated by reference because the value is being modified twice: once by the gesture and once by the setWtf function.
Using a different variable to hold the current screen index and only updating the value of state.index when the user interacts with the buttons is one potential fix for this problem. This should prevent the screen from being displayed more than once and ensure that the value of state.index is only modified once.
It's important to keep in mind that the setWtf function you specified in your query could not be connected to the problem you're having. Without more information, it's difficult to say for sure whether this function is being used to update another state in your application.

Performance issues if MapComponent state is updated

I am not sure if this is an issue of react-leaflet-markercluster, react-leaflet, leaflet, react, or my code.
I have a map with several thousand markers and I am using react-leaflet-markercluster for marker clustering. If I need to update a global state of MapComponent, there is 1-3 seconds delay when this change is reflected.
I created a codesandox with 5000 markers and you can see there 2 use cases with performance issues:
1.) MapComponent is inside react-reflex element, that allows resizing panel and propagates new dimensions (width, height) to MapComponent. If width and height are changed, mapRef.invalidateSize() is called to update map dimensions. Resizing is extremely slow.
2.) If user clicks on Marker, global state selected is updated. It is a list of clicked marker ids. Map calls fitBounds method to focus on clicked marker and also marker icon is changed. There is around 1 second delay.
In my project, if I need to change a MapComponent state, it takes 2-3 seconds in dev mode when changes are reflected and it is just a single rerender of MapComponent and its elements (markers).
I took a look at Chrome performance profile and it seems like most time is spent in internal React methods.
It is possible to fix this by preventing rerendering using memo, which is similar to shouldComponentUpdate, but it makes whole code base too complicated. preferCanvas option doesn't change anything. I am wondering what is a good way to fix these issues.
The main problem I identified in your code is that you re-render the whole set of marker components. If you memoize the generation of those, you achieve a good performance boost; instead of running the .map in JSX, you can store all the components in a const; this way, the .map won't run on every render.
from this
...
<MarkerClusterGroup>
{markers.map((marker, i) => {
...
to something like this
const markerComponents = React.useMemo(() => {
return markers.map((marker) => {
return (
<MarkerContainer .../>
);
});
}, [markers, onMarkerClick]);
return (
<>
<MarkerClusterGroup>{markerComponents}</MarkerClusterGroup>
</>
);
The second refactor I tried is changing the way you select a marker. Instead of determining the selected prop from the selected array for each marker, I put a selected field on every marker object and update it when selecting a marker. Also, I add the position to the onClickHandler args to avoid looking for that in the markers array.
There are some other tweaks I don't explain here so please check my codesandbox version.
https://codesandbox.io/s/dreamy-andras-tfl67?file=/src/App.js

Why a React app freezes on mobile devices? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I made a small app using react and it works smoothly on my computer. However, when I open it on different mobile devices it crashes after a minute or so of usage. I don't know what causes the problem but weirdly enough I don't have any bugs or warnings on my console and haven't used componentDidUpdate or hooks that might cause infinite loops like useEffect. Please help me if you know what causes a react app to glitch on mobile devices or have encountered the same problem and found a solution for it.
Here's the app
https://summerresort.netlify.app
and the code
https://github.com/Mahmoud-farargy/summerresort/tree/master/Beach-Resort
Thanks!
Your app looks all ok except 2 points. I can't test my guess, but I'm almost entirely sure that your problem comes from those 2.
Both parts that seem problematic are located in index.js, here there are:
window.addEventListener("scroll", () => {// gets the current height
let scroll = document.body.scrollTop || document.documentElement.scrollTop;
let arrowUp = document.querySelector(".arrow-up-btn").style;
scroll >= 1000 ? arrowUp.display="flex" : arrowUp.display = "none";
});
window.addEventListener("resize", ()=> {// gets the current width
this.setState({
currentPageWidth: window.innerWidth || document.documentElement.clientWidth
})
});
The first code block is expensive because:
The scroll event is fired very frequently.
You don't listen for scroll passively (it'd be a good idea though).
You set the style much more frequently than needed.
However, I think, that it is the second code block that causes mobiles to glitch.
Check out this answer to see why the resize event is fired on mobiles more frequently than on desktop.
Now, each time the resize event is triggered, the state of MainApp
is updated.
Each time MainApp is updated, React recalculates all its children.
By default, React just re-run render of each child & compares the output.
Considering you have all routes & all components inside the MainApp & you didn't implement any optimizations (React.PureComponent, lazy loading for routes, etc.) React will have to recalculate what the entire site looks like on each resize event.
The easiest fix would be to store currentPageWidth in a ref instead of state.
Another possible problem is that by attaching listeners inside the render method, you're attaching new listeners on each single render without clearing any of previously added listeners.

Infinite loop inside useEffect while trying to use Firebase

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

React stackable snackbars/toasts

I'm creating my own simple snackbar/toast stacker. However, I'm having problems with queing them in an orderly manner. Removing a snackbar from the snackbar que causes re-render and odd behavior.
The basic flow:
Click a button which causes the addSnack function to fire which is provided by the withSnackbar HOC.
Take the parameters from the fired function, and create a snack accordingly and add it to the snackbar list.
At the end, we render the snackbar list.
Each snackbar controls it's own appearance and disappearance, and is controlled by a time out. After the timeout is fired, it calls removeSnack function which is suppose to remove the first snack from the list.
codesandbox
If you click the button for example, four times in a short amount of time. They render nicely, but when the first one is to be deleted, they all disappear and reappear abnormally.
I understand that it's partially the state re-renderings fault, however, I'm not sure how to handle it in a way that the removal is handled gracefully without affecting the rendering of other snacks.
So, after many hours of trial and error, I found a solution that works so far. Moving and reading the snacks outside of the state helped with the bizarre rendering problems, and with it, I was able to create a message que which works well.
Working example
Codesandbox
If you look at splice document, you will notice that it's returning an array of deleted elements and not the initial array.
You can correct it by splicing then updating:
snacks.splice(-1, 1);
addSnacks(snacks);
However you are still going to have some weird behavior and you might need to use a keyed list to fix that.
i had the same issue and i saw your solution, but i was really trying to find out why it happens - here is why:
when u call a useState hook from an async function's callback, you should use the callback format of the hook to make sure that you are working with the latest value. example:
const [messages, setMessages] = useState([]);
const addMessage = ( message ) => {
setMessages( prevMessages => {//prevMessages will be the latest value of messages
return [ ...prevMessages, message ];
});
};
const removeMessage = ( index ) => {
setMessages( prevMessages => {//prevMessages will be the latest value of messages
let newMessages = [...prevMessages];
newMessages.splice( index, 1 );
return newMessages;
});
};

Resources