React useEffect 不会更改地图上显示的数据

React useEffect doesn't change data displayed on map

我正在使用 uber 的 react-map-gldeck-gl 库来尝试显示数据 dynamically.I我的有 2 个组件对 app.A 导航栏和 Mapbox map 反应不大。所以这是我的 pipeline.When 页面第一次加载,只有地图显示没有任何标记或视觉 data.But 当我点击导航栏 link 之一,一个 action creator 被调用,当我进行 ajax 调用以获取一些数据时,并从分派的操作中传递我的响应数据作为有效负载和达到 reducer 以便我有一个新版本的 store.the 数据,我想在它们的存储键中可视化:mainProjects 包含一个数组 geojson.My单击导航栏 link 成功更新该值,在实际的 Map 组件中,我可以加载新值但 useEffect 不更新我的 localstate.Here 是我的地图代码:

import React, { useState, useEffect, useContext } from "react";
import { StaticMap } from "react-map-gl";
import { MapContext } from "./contexts/MapProvider";
import DeckGL, { GeoJsonLayer } from "deck.gl";
import chroma from "chroma-js";
import { connect } from "react-redux";

const MAPBOX_TOKEN =
  "pk.mykey";
const mapStyle = "mapbox://mymapstyle";

function getEnergyFillColor(regime) {
  const ENERGY_COLORS = {
    naturalGaz: "#FF8500",
    coal: "#99979A",
    nuclear: "#E0399E",
    hydroelectric: "#0082CB",
    Wind: "#00B53B",
    solar: "#DBCA00",
    oil: "#FF0009",
    other: "#FFEFD3"
  };

  let color;
  switch (regime) {
    case "Hydraulique":
      color = ENERGY_COLORS.hydroelectric;
      break;
    case "Thermique":
      color = ENERGY_COLORS.nuclear;
      break;
    default:
      color = ENERGY_COLORS.other;
      break;
  }
  color = chroma(color)
    .alpha(0.667)
    .rgba();
  color[3] *= 255;
  return color;
}

function _onClick(info) {
  if (info.object) {
    // eslint-disable-next-line
    alert(
      `${info.object.properties.NOM} (${info.object.properties.PROVINCE}) - ${
        info.object.properties.PUISSANCE
      }MW`
    );
  }
}

function Map({ mainProjects }) {
  const { viewport, setViewport, onLoad } = useContext(MapContext);
  const [airports, setAireports] = useState();
  const [electricalEnergy, setElectricalEnergy] = useState();
  const [hospitals, setHospitals] = useState();
  const [roads, setRoads] = useState();
  useEffect(() => {
    if (mainProjects.length) {
      setHospitals(mainProjects[0].hospitals);
      setAireports(mainProjects[1].aeroports);
      setElectricalEnergy(mainProjects[2].electricite);
      setRoads(mainProjects[2].routes);
    }
  }, [airports, electricalEnergy, hospitals, roads]);
  const layers = [
    //ENERGIE ELECTRIQUE
    new GeoJsonLayer({
      id: "energy",
      data: electricalEnergy,
      // Styles
      filled: true,
      pointRadiusMinPixels: 20,
      opacity: 1,
      pointRadiusScale: 2000,
      getRadius: energyItem => energyItem.properties.puissance * 3.14,
      getFillColor: energyItem =>
        getEnergyFillColor(energyItem.properties.regime),
      // Interactive props
      pickable: true,
      autoHighlight: true,
      onClick: _onClick
    }),

    //AEROPORTS
    new GeoJsonLayer({
      id: "airports",
      data: airports,
      // Styles
      filled: true,
      pointRadiusMinPixels: 20,
      opacity: 1,
      pointRadiusScale: 2000,
      getRadius: energyItem => energyItem.properties.PUISSANCE * 3.14,
      getFillColor: energyItem =>
        getEnergyFillColor(energyItem.properties.REGIME),
      // Interactive props
      pickable: true,
      autoHighlight: true,
      onClick: _onClick
    }),

    //HOSPITALS
    new GeoJsonLayer({
      id: "hospitals",
      data: hospitals,
      // Styles
      filled: true,
      pointRadiusMinPixels: 20,
      opacity: 1,
      pointRadiusScale: 2000,
      getRadius: energyItem => energyItem.properties.PUISSANCE * 3.14,
      getFillColor: energyItem =>
        getEnergyFillColor(energyItem.properties.REGIME),
      // Interactive props
      pickable: true,
      autoHighlight: true,
      onClick: _onClick
    }),

    //ROUTES
    new GeoJsonLayer({
      id: "roads",
      data: roads,
      pickable: true,
      stroked: false,
      filled: true,
      extruded: true,
      lineWidthScale: 20,
      lineWidthMinPixels: 2,
      getFillColor: [160, 160, 180, 200],
      getLineColor: d => [255, 160, 20, 200],
      // getLineColor: d => colorToRGBArray(d.properties.color),
      getRadius: 100,
      getLineWidth: 1,
      getElevation: 30,
      onHover: ({ object, x, y }) => {
        // const tooltip = object.properties.name || object.properties.station;
        /* Update tooltip
           http://deck.gl/#/documentation/developer-guide/adding-interactivity?section=example-display-a-tooltip-for-hovered-object
        */
      },
      onClick: _onClick
    })
  ];

  return (
    <>
      <link
        href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css"
        rel="stylesheet"
      />
      <DeckGL
        initialViewState={viewport}
        viewState={viewport}
        controller={true}
        layers={layers}
        onLoad={onLoad}
        onViewportChange={nextViewport => setViewport(nextViewport)}
      >
        <StaticMap mapboxApiAccessToken={MAPBOX_TOKEN} mapStyle={mapStyle} />
      </DeckGL>
    </>
  );
}

const mapStateToProps = ({
  selectedLinks: { sectorSelected, provinceSelected, subSectorSelected },
  mainProjects
}) => {
  if (sectorSelected || provinceSelected || subSectorSelected) {
    return {
      mainProjects
    };
  } else {
    return {
      mainProjects: []
    };
  }
};
export default connect(mapStateToProps)(Map);

在上面的代码中,我尝试通过 is setter 更新我的本地状态值,但是 useEffect 似乎没有 work.And 它看起来只被调用一次,当组件渲染第一个 time.How 我可以解决这个问题吗?

谢谢!!

您的 useEffect 具有一组与实际使用的不匹配的依赖项。 您正在使用 mainProjects 的元素设置本地状态,因此 useEffect 只会在 mainProjects 更改时执行某些操作。

你似乎没有对你的 useState-Variables 做任何事情,所以你没有改变状态,所以 React 没有重新渲染。

更新:检查依赖数组(useEffect 的第二个参数)和函数内使用的变量(第一个参数)是否对应非常重要,否则会发生不好的事情;-)

有一个 eslint 规则:https://www.npmjs.com/package/eslint-plugin-react-hooks