Search code examples
javascriptreactjsleafletreact-leafletpapaparse

useState returning a 172 object array 172 times instead of the single object with 172 fields


So I am using React to pull Covid-19 data from a CSV using papaparse. I then filter this array to only show results from today. I am using a functional react component like so:

import React, { Component, useState, useEffect } from 'react';
import Papa from 'papaparse'
import dataJSON from './data/CovidLocations.json'
import {Tooltip, Circle } from "react-leaflet";

const DashBoard = (props) => {
    const [data, setDataArr] = useState([]);
    const [dailyResults, setDailyResults] = useState([]);


    useEffect(() => {    
        getData()
    }, [dailyResults]); 

    const getData = () => {
        Papa.parse("https://raw.githubusercontent.com/tomwhite/covid-19-uk-data/master/data/covid-19-cases-uk.csv", {
            download: true,
            header: true,
            complete: (results) => {
                var data = results.data
                setDataArr(data)
                setData(data)
            }
        });
    }

    const setData = (data) => {
        let merged = [];
        let result = [];

        for(let i=0; i< data.length; i++) {
            merged.push({
             ...data[i], 
             ...(dataJSON.find((itmInner) => itmInner.Location === data[i].Area))}
            );  
        }

        result = merged.filter(obj => {
            return obj.Date === "2020-04-02"
        });

        let output = result.filter(obj => Object.keys(obj).includes("Latitude"));

        setDailyResults(output)
        console.log(dailyResults)

    }


        return(
            <div>
            {dailyResults &&
            dailyResults.map(({Location, Latitude, Longitude, TotalCases}, i) => (
            <Circle
                key={`markers-${i}`}
                center={[Latitude, Longitude]}
                radius={35 * TotalCases}
                fillColor="red"
                color="black"
                weight="0.5"
            >
                <Tooltip>
                <span>
                    <b>Location</b>: {Location}
                    <br />
                    <b>Total Cases</b>: {TotalCases}
                </span>
                </Tooltip>
            </Circle>
            ))}
            </div>
        )

}

export default DashBoard;

At line 46 here console.log(dailyResults) it returns the object correctly, mapped with the other json object, but it then iterates through the object 172 times (the same number of array values). What I need is this code to execute, map the array from the CSV, add the latlngs (all which works fine) but then in the return statement I need the array of 172 to not keep looping so It can be passed into react-leaflet as an object to create map markers. It seems like a simple issue, I just do not know how to implement it.

dataJSON format:

  {
    "Location": "Barking and Dagenham",
    "Latitude": 53.546299,
    "Longitude": -1.46786
  }

Solution

  • dailyResults is changing multiple times because you are looping over a lot of data, so probably you are requesting also multiples times csv data then you should probably take an infinite loop and your browser stack as you change also output variable as many times as you are looping over data variable.

    So what I understand you want to achieve is to extract the Location, Latitude and Longitude from the dataJSON and also extract the TotalCases from the csv by comparing Area with Location. If that is the case you can do it in a simple way:

    After parsing the data from the csv, loop over dataJSON and data like this using a constant variable to push an object with the above mentioned data you want to include:

      let dailyResults = [];
    
      data.find((csv) => {
        dataJSON.forEach((json) => {
          if (csv.Area === json.Location) {
            dailyResults.push({
              Location: json.Location,
              Latitude: json.Latitude,
              Longitude: json.Longitude,
              TotalCases: csv.TotalCases,
            });
          }
        });
      });
    

    and remove dailyResults from dependency array:

     useEffect(() => {
        getData();
      }, []);
    

    Demo