#javascript #reactjs #api #leaflet
#javascript #reactjs #API #листовка
Вопрос:
Я создаю Corona Virus tracker в React, который отображает данные на карте листовки Choropleth. У меня есть файл data.json, который содержит данные полигона для рисования границ для этой карты. Идея в том, чтобы добавить данные COVID из API в этот файл data.json, вернуть этот объект и передать его в качестве реквизита в компоненте карты. В компоненте карты функция загрузки страны выполняется для каждого объекта в компоненте GeoJSON на карте. При этом отображаются данные о COVID с цветовой кодировкой каждой страны в зависимости от количества случаев COVID. Проблема в том, что иногда данные загружаются некорректно, и карта отображается серым цветом.
Я пробовал несколько способов, включая добавление тайм-аута, который заставлял его работать в 80% случаев, но иногда он все равно не работает.
World.js файл:
import React, { useState, useEffect } from "react";
import "./App.css";
import {
Card,
CardContent,
} from "@material-ui/core";
import Table from "./Table";
import { sortData} from "./Helper";
import Map from "./Map";
import { features } from "./data/countries.json";
import "leaflet/dist/leaflet.css";
const World = () => {
const [countries, setCountries] = useState([]);
const [mapCountries, setMapCountries] = useState([]);
const [tableData, setTableData] = useState([]);
const [casesType, setCasesType] = useState("cases");
const [mapZoom, setMapZoom] = useState(3);
const attachCovidData = () => { //Attach covid data to newFeatures
const newFeatures = [];
for (let i = 0; i < features.length; i ) {
newFeatures.push(features[i]);
}
for (let i = 0; i < newFeatures.length; i ) {
const featureCountry = newFeatures[i];
featureCountry.cases = 0;
featureCountry.casesText = "";
const covidCountry = tableData.find(
(country) =>
country.countryInfo.iso3 === featureCountry.properties.ISO_A3
);
if (covidCountry != null) {
let cases = covidCountry.cases;
let deaths = covidCountry.deaths;
featureCountry.cases = cases;
featureCountry.opacityLevel = 0;
if (featureCountry.cases < 50000) {
featureCountry.opacityLevel = 0.1;
} else if (featureCountry.cases < 50000) {
featureCountry.opacityLevel = 0.2;
} else if (
featureCountry.cases >= 50000 amp;amp;
featureCountry.cases < 100000
) {
featureCountry.opacityLevel = 0.3;
} else if (
featureCountry.cases >= 100000 amp;amp;
featureCountry.cases < 250000
) {
featureCountry.opacityLevel = 0.4;
} else if (
featureCountry.cases >= 250000 amp;amp;
featureCountry.cases < 500000
) {
featureCountry.opacityLevel = 0.5;
} else if (
featureCountry.cases >= 500000 amp;amp;
featureCountry.cases < 1000000
) {
featureCountry.opacityLevel = 0.6;
} else {
featureCountry.opacityLevel = 1;
}
featureCountry.deaths = deaths;
featureCountry.casesText = "";
}
}
console.log(newFeatures);
return newFeatures;
};
useEffect(() => {
const getCountriesData = async () => {
fetch("https://disease.sh/v3/covid-19/countries") // Get covid data
.then((response) => response.json())
.then((data) => {
const countries = data.map((country) => ({
name: country.country,
value: country.countryInfo.iso2,
}));
let sortedData = sortData(data);
setCountries(countries);
setMapCountries(data);
setTableData(sortedData);
});
};
getCountriesData();
}, []);
return (
<div className="app">
<div className="app__left">
<div className="app__header">
<h1>World Overview</h1>
</div>
<Map
countries={mapCountries}
casesType={casesType}
center={{ lat: 34.80746, lng: -40.4796 }}
zoom={mapZoom}
newFeatures={attachCovidData()}
/>
</div>
<Card style = {{marginTop: '50px'}} className="app__right">
<CardContent>
<div className="app__information">
<h3>Total Cases</h3>
<Table countries={tableData} />
</div>
</CardContent>
</Card>
</div>
);
};
export default World;
Map.js файл
import React, { useState, useEffect } from "react";
import { MapContainer as LeafletMap, TileLayer, GeoJSON } from "react-leaflet";
import "./Map.css";
import "leaflet/dist/leaflet.css";
function Map({ countries, center, zoom, newFeatures }) {
const [loadedMap, setLoadedMap] = useState(false);
useEffect(() => {
setTimeout(() => {
setLoadedMap(true);
}, 1000);
}, []);
const countryLoad= (country, layer) => {
const name = country.properties.ADMIN;
const confirmedCases = country.cases;
const confirmedCasesCommas = confirmedCases
.toString()
.replace(/B(?=(d{3}) (?!d))/g, ",");
const confirmedDeaths = country.deaths;
const opacityLevel = country.opacityLevel;
console.log(confirmedCases);
layer.options.fillColor = `rgba(0,0,255, ${country.opacityLevel}`;
layer.bindPopup(`${name} ${confirmedCasesCommas} `);
};
console.log(newFeatures);
const map = (
<div className="map">
<LeafletMap center={center} zoom={zoom}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='amp;copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
/>
<GeoJSON
data={newFeatures}
style={{ weight: 0.7 }}
onEachFeature={countryLoad}
/>
</LeafletMap>
{console.log(countries)}
</div>
);
return loadedMap?map:null;
}
export default Map;
Комментарии:
1. Что вы имеете в виду, говоря » иногда данные загружаются некорректно »
2. Извините, я должен уточнить. Каждая страна отображается серым, а не фиолетовым оттенком, с более темными оттенками, представляющими большее количество случаев covid. Таким образом, в значительной степени данные, отправляемые в качестве реквизита в файл карты, в некоторых случаях неточны
Ответ №1:
Похоже, проблема связана с рендерингом до получения фактических данных из конечной точки.
Вам нужно будет переместить const [loadedMap, setLoadedMap] = useState(false);
логику в World
компонент и установить флаг true
только после того, как конечная точка вернет данные.
Итак, завершите рендеринг карты (в World
компоненте) с помощью
{Boolean(mapCountries.length) amp;amp; (<Map
countries = { mapCountries }
casesType = { casesType }
center = {{ lat: 34.80746, lng: -40.4796 }}
zoom = { mapZoom }
newFeatures = { attachCovidData() }
/>)}
и удалите все loadedMap
из Map
компонента