[Bug] Race Condition during event handlers initialization
Description
Due to how this library binds event handlers to the google maps object there is a race condition. Events might be fired before react event handler is attached to the map. The simplest example is onProjectionChanged:
Steps to Reproduce
const App = () => {
const onProjectionChanged = useCallback(function onProjectionChanged() {
console.log("onProjectionChanged");
}, []);
const onBoundsChanged = () => {
console.log("onBoundsChanged");
};
console.log("render app");
return (
<APIProvider apiKey={API_KEY}>
<Map
zoom={3}
center={{ lat: 22.54992, lng: 0 }}
gestureHandling={"greedy"}
disableDefaultUI={true}
onProjectionChanged={onProjectionChanged}
onBoundsChanged={onBoundsChanged}
onClick={() => console.log("click")}
/>
<ControlPanel />
</APIProvider>
);
};
Try to reload map few times, and onProjectionChanged called not every time.
This happened due to map instance created in one useEffect and events bound in another. They are executed in diffrent async cycles, so map sometimes managed to fire an event before handler attached.
PS I tried to create a codesandbox with an issue, but in the sandbox no events were fired at all https://codesandbox.io/p/devbox/amazing-bohr-v65hqw
Environment
- Library version: 0.4.1
- Google maps version: 3.55.4
- Browser and Version: Chrome 120
- OS: MacOs Sonoma 14.1.2
Logs
No response
I can see why it's happening, but I don't have a good Idea how to fix it properly.
- the map instance is created in an effect in the
useMapInstance()hook and stored in a state variable: https://github.com/visgl/react-google-maps/blob/9422f03d18cafd98ae161706e3ca797a35407db2/src/components/map/index.tsx#L185-L217 - that state variable is then passed on to the
useMapEvents()hook where event-handlers are attached in another effect-hook: https://github.com/visgl/react-google-maps/blob/9422f03d18cafd98ae161706e3ca797a35407db2/src/components/map/index.tsx#L86-L90
So there could be a very short gap between creating the map instance / the setMap call and adding, since I think the setMap will cause a re-render and the updated map-value will only be available in the next render cycle, which is probably enough time for the maps api to initialize and trigger the initial events.