Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Race Condition during event handlers initialization #136

Open
timofei-iatsenko opened this issue Dec 21, 2023 · 1 comment
Open

[Bug] Race Condition during event handlers initialization #136

timofei-iatsenko opened this issue Dec 21, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@timofei-iatsenko
Copy link
Contributor

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 timofei-iatsenko added the bug Something isn't working label Dec 21, 2023
@usefulthink
Copy link
Collaborator

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:
    useEffect(
    () => {
    if (!container || !apiIsLoaded) return;
    const {addMapInstance, removeMapInstance} = context;
    const newMap = new google.maps.Map(container, mapOptions);
    setMap(newMap);
    addMapInstance(newMap, id);
    if (initialBounds) {
    newMap.fitBounds(initialBounds);
    }
    return () => {
    if (!container || !apiIsLoaded) return;
    // remove all event-listeners to minimize memory-leaks
    google.maps.event.clearInstanceListeners(newMap);
    setMap(null);
    removeMapInstance(id);
    };
    },
    // FIXME: we should rethink if it could be possible to keep the state
    // around when a map gets re-initialized (id or mapId changed). This
    // should keep the viewport as it is (so also no initial viewport in
    // this case) and any added features should of course get re-added as
    // well.
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [id, container, apiIsLoaded, props.mapId]
    );
  • that state variable is then passed on to the useMapEvents() hook where event-handlers are attached in another effect-hook:
    const [map, mapRef] = useMapInstance(props, context);
    const cameraStateRef = useInternalCameraState();
    useMapOptions(map, cameraStateRef, props);
    useMapEvents(map, cameraStateRef, props);
    useDeckGLCameraUpdate(map, viewState);

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants