U. Watt
U. Watt

Reputation: 724

Warning: The final argument passed to useMemo changed size between renders. The order and size of this array must remain constant

I'm getting markers when location is entered by the user, and the markers list is then provided to the Google Maps component. Since I don't want the map to re-render everytime, I have memoized it. It only re-renders when the markers props changes. But when markers changes, I get the following warning:

Warning: The final argument passed to useMemo changed size between renders. The order and size of this array must remain constant.

I followed answers in the other posts, and none worked for me. What am I doing wrong?

const [plants, setPlants] = useState([
    {
      name: "Plant 1",
      id: uuidv4(),
      location: "",
      coords: {},
      country: "",
      isOffshore: false,
    },
  ]);

  const isObjectEmpty = (obj) => {
    for (var i in obj) return false;
    return true;
  };

  const getMarkers = () => {
    var temp = [];
    for (var i = 0; i < plants.length; i++)
      if (!isObjectEmpty(plants[i].coords)) temp.push(plants[i].coords);
    return temp;
  };

  const markers = useMemo(
    () => getMarkers(),
    [...plants.map((item) => item.coords)]
  );

My map component:

const MapContainer = React.memo((props) => {
  const [map, setMap] = useState();
  const [center, setCenter] = useState({ lat: 59.913, lng: 10.75 });
  var bounds = new props.google.maps.LatLngBounds();

  const setMapObj = (mapProps, map) => {
    setMap(map);
  };

  useDeepCompareEffect(() => {
    console.log(props.markers);
    if (props.markers.length < 1) return;
    setCenter(props.markers[props.markers.length - 1]);
    //this is to zoom out the map by bit;
    //we provide bounds but not the marker
    // if (props.markers.length === 1) {
    //   bounds.extend(
    //     new props.google.maps.LatLng(props.markers[0].lat, props.markers[0].lng)
    //   );
    //   bounds.extend(
    //     new props.google.maps.LatLng(
    //       props.markers[0].lat - 1,
    //       props.markers[0].lng - 1
    //     )
    //   );
    //   map && map.fitBounds(bounds);
    //   return;
    // }
    // for (var i = 0; i < props.markers.length; i++) {
    //   bounds.extend(
    //     new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
    //   );
    // }
    // if (map) {
    //   map.fitBounds(bounds);
    // }
  }, [props.markers, map]);

  return (
    <div className={props.className}>
      <Map
        google={props.google}
        style={{ borderRadius: "10px" }}
        center={center}
        initialCenter={{ lat: 59.913, lng: 10.75 }}
        onReady={setMapObj}
        zoom={7}
      >
        {props.markers.map((item, index) => {
          if (item.lat && item.lng)
            return (
              <Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
            );
        })}
      </Map>
    </div>
  );
});

Upvotes: 1

Views: 7019

Answers (1)

Someone Special
Someone Special

Reputation: 13588

 const markers = useMemo(
    () => getMarkers(),
    [...plants.map((item) => item.coords)]
  );

If the coordinates are for example [[1,2],[3,4],[4,5]], you are actually passing [[1,2],[3,4],[4,5]] as dependency.

You should probably just use

 const markers = useMemo(
    () => getMarkers(),
    [plants]
  );

Upvotes: 2

Related Questions