algolia / react-instantsearch

⚡️ Lightning-fast search for React and React Native applications, by Algolia.
https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/
MIT License
1.97k stars 386 forks source link

`GoogleMapsLoader` instantly unmounts, not rendering Map #3678

Closed joepio closed 1 year ago

joepio commented 1 year ago

Hi there! First off, thanks for maintaining this really nice library :)

I'm kind of stuck with react-instantsearch-dom, as you can read below, but maybe I should migrate to react-instantsearch-hooks-web anyway.

🐛 Bug description

I'm trying to render a map using GoogleMapsLoader and GeoSearch, but fail to render anything. I've set a height in the parent, so that's not it.

There are no errors in the console, and the network responses look good - I can see that Google's API is responding with 200s. And window.google is in fact a google object, so I suppose the googles js code is running just fine.

I've tried reproducing the bug in CodeSandbox, but to no avail. It just works there.

The lambda in the children of GeoSearch is never called. If I put a console.log in, It never shows. So for some reason something goes wrong in GoogleMapsLoader.

This condition is always false, because this.isUnmounting seems to always be true in my case.

// GoogleMapsLoader.js 
        if (!this.isUnmounting) {
          this.setState(() => ({
            google: window.google,
          }));
        }

So the google state is never set, and this always returns null:

      if (!this.state.google) {
        return null;
      }

this.isUnmounting is practically always set to true, because componentWillUnmount is called early on.

  componentWillUnmount() {
    this.isUnmounting = true;
  }

I thought this is supposed to be called only when a component will unmount?

Code

import React from "react";
import {
  GoogleMapsLoader,
  GeoSearch,
  Control,
  Marker,
} from "react-instantsearch-dom-maps";
import { mapsKey } from "./config";
import './Map.css';

export const Map = () => {
  return (
    <div className="Map">
      <GoogleMapsLoader apiKey={mapsKey}>
        {(google) => {
          console.log('google', google);

          return (
          <GeoSearch google={google}>
            {({ hits }) => (
              <div>
                <Control />
                {hits.map((hit) => (
                  <Marker key={hit.objectID} hit={hit} />
                ))}
              </div>
            )}
          </GeoSearch>
        )}}
      </GoogleMapsLoader>
    </div>
  );
};

Environment

Haroenv commented 1 year ago

Does this reproduce in a clean-slate React InstantSearch implementation on your local machine or also not? I wonder if it could be related to strict mode / react 18 possibly? Have you tried if changing either of those made a difference?

joepio commented 1 year ago

Thanks for the quick reply, @Haroenv!

Indeed, removing React.StrictMode seemed to fix it! I also had to manually set some CSS properties (height: 100%).

componentWillUnmount() is always called in strict mode or something?

Thanks!

Haroenv commented 1 year ago

This is thus indeed a bug in the maps package, which unmounts, but not correctly remounts. Strict mode calls the life cycle functions multiple times and this code wasn't written with that in mind.

As we haven't migrated the maps package to react hooks yet, I'd recommend staying with React InstantSearch dom for now.

Is avoiding strict mode an option for you in the mean time?

joepio commented 1 year ago

Avoiding strict mode is fine for me for now, thanks for helping out!

nathan-schmidt-viget commented 1 year ago

Had the same problem, removed React.StrictMode fixed it.

FabienMotte commented 1 year ago

We're doing a round of cleanup before migrating this repository to the new InstantSearch monorepo. This issue seems not to have generated much activity lately and is to be mostly solved, so we're going to close it. Feel free to reopen it if needed.