当 props 没有改变时组件被重新渲染

Component getting re-rendered when props aren't changing

我正在展示一张使用 React.memo() 记忆的地图。我希望地图仅在道具更改时重新渲染,但即使道具不更改也会重新渲染。当 props 没有改变时,如何防止重新渲染?

地图:

const MapContainer = React.memo((props) => {
  const [map, setMap] = useState();
  var bounds = new props.google.maps.LatLngBounds();

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

  useDeepCompareEffect(() => {
    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={{ lat: 59.913, lng: 10.75 }}
        initialCenter={{ lat: 59.913, lng: 10.75 }}
        onReady={setMapObj}
        zoom={8}
      >
        {console.log("rendered")}
        {props.markers.map((item, index) => {
          if (item.lat && item.lng)
            return (
              <Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
            );
        })}
      </Map>
    </div>
  );
});

export default GoogleApiWrapper({
  apiKey: "API_KEY",
})(MapContainer);

由于父组件很大,我只添加了我认为相关的部分。 地图的父级:

function Home() {
  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;
  };

  return (
    <section/>
    <CustomMap className="map" markers={getMarkers()} />
    <section/>
  )
}
  1. 备忘录没有做深度比较
  2. 每次回家都是re-render,地图也会是re-render。因为 您正在传递标记作为执行函数的结果 每次生成一个新的数组,一个新的引用,指向不同的 目的。这当然被备忘录视为触发 re-render。除了新数组,请记住 getMarkers 函数每次也是新的,指的是不同的 目的。对于函数,通常使用useCallback。
  3. 我建议使用 useMemo 钩子来修复和排除创建 一个新数组,相应地,一个对新对象的引用。和 因此,在不需要时将不会 re-rendering。
  4. 不要忘记在 useMemo 中包含依赖项。在你的情况下是 植物。

例子

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