visgl / react-google-maps

React components and hooks for the Google Maps JavaScript API
https://visgl.github.io/react-google-maps/
MIT License
1.32k stars 111 forks source link

[Bug] Race Condition during event handlers initialization #136

Open timofei-iatsenko opened 11 months ago

timofei-iatsenko commented 11 months ago

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

Logs

No response

usefulthink commented 10 months ago

I can see why it's happening, but I don't have a good Idea how to fix it properly.

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.