I have a map which has an overlay. I have an effect which, when the underlying data changes, deletes the old overlay and re-draws a new one.
Of note, I'm using "react-hooks/exhaustive-deps"
and it seems from everything I read that just removing the dependency overlay
is not the right answer (but it does work).
Of note, data is a prop passed in.
useEffect(() => {
// remove the overlay if it is there,
// I should have overlay as a dependency per exhaustive-reps react eslint rule
if (overlay) map.removeOverlays(overlay);
// Generate the new overlay based on the new data (useCallback function)
const newOverlay = generateNewOverlay(data)
// Store the new overlay so I can remove it later if the data changes
// Doesn't need to be done right away though, just before next render
setOverlay(newOverlay);
// Show the new overlay on my map
map.addOverlays(newOverlay);
}, [map, overlay, data, generateNewOverlay]);
This of course will be an infinite loop because I'm setting overlay and making it a dependency. I also don't like using setState immediately in an effect as it causes another render. What am I missing? How do I achieve this logic?
I did read about 5 similarly titled questions, but they did not answer my question.
Similar question, but not asking while keep exhaustive-reps deps lint rule which isn't a factor for them because they aren't reading the state before changing it.
Edit:
I still have the problem where useState and a reducer should be pure. The purpose of the dependency I'm having an issue with (overlay
) is that I have to check if overlay exists. If it does, I need to do a non-pure thing which is remove that overlay from the map before setting my new overlay. This line of code is what makes it not pure:
if (overlay) map.removeOverlays(overlay);
Without that line, I'd never need overlay
in my dependency list and this entire thing wouldn't be a factor. As you can see the accepted answer is not pure because of that line.
The useReducer answer has this line outside the reducer so overlay
should be a dependency or it needs to go in the reducer. The first option is what I'm trying to avoid by the "react-hooks/exhaustive-deps"
and the second answer is not pure.
Appreciate any help.
Final Edit:
I found the best way to approach this was to use the cleanup in useEffect properly. I was requiring state so that I could remove things from a map later.
useEffect(() => {
// remove the overlay if it is there,
// I originally needed this to store the overlay so I could remove it later, but if I use cleanup properly this isn't needed
// if (overlay) map.removeOverlays(overlay);
// Generate the new overlay based on the new data (useCallback function)
const newOverlay = generateNewOverlay(data)
// Store the new overlay so I can remove it later if the data changes
// Doesn't need to be done right away though, just before next render (This is what a cleanup is!)
// setOverlay(newOverlay);
// Show the new overlay on my map
map.addOverlays(newOverlay);
// New code below
return () => {map.removeOverlays(newOverlay)};
}, [map, data, generateNewOverlay]);