0

我正在使用uber react-map-gldeck-gl库来尝试动态显示数据。我的反应小应用程序中有 2 个组件。一个导航栏和一个Mapbox map。所以这是我的管道。当页面第一次加载时,只显示地图没有任何标记或可视数据。但是当我单击导航栏之一时linkaction creator会调用一个,当我ajax调用以获取一些数据时,并且从调度的操作中将我的响应数据作为有效负载传递并reducer达到我有一个新版本的商店。我想在他们的存储键中可视化的数据:mainProjects包含一个数组。geojson我点击导航栏链接成功更新了该值,在实际Map组件中,我可以加载新的价值观,但useEffect不更新我的本地状态。这是我的地图代码:

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似乎不起作用。看起来它只被调用一次,在组件第一次呈现时。我该如何解决这个问题?

谢谢!!

4

1 回答 1

1

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

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

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

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

于 2019-08-13T11:18:02.560 回答