react-google-maps icon indicating copy to clipboard operation
react-google-maps copied to clipboard

[Bug] Race Condition during event handlers initialization

Open timofei-iatsenko opened this issue 2 years ago • 1 comments

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

timofei-iatsenko avatar Dec 21 '23 09:12 timofei-iatsenko

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.

usefulthink avatar Jan 18 '24 12:01 usefulthink