Данные на карте JS листовки отображаются некорректно

#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 компонента