Papa.parse componentDidMount shouldComponentUpdate confusion

by Nick Carducci   Last Updated September 11, 2019 13:26 PM

Edit: I think this is a CORS issue with codesandbox, but I haven't figured out how to host with static ip or even localhost yet. I'll update when I can confirm it is a CORS issue between papaparse and codesandbox cloud ide. I started a new question for a different problem than Domino solved on the same papaparse application

This question here on StackOverflow is an extension of my conversation with Papa.parse.

A pattern is found here, similarly I use a this.function to pass down every object as it is parsed with "City" parameter & try to render a "WeatherCitySkyMap" component for each City. The code after render has been tested to render such a component for each City in the cities array if I hard code let cities = [{ city: "New York" }, { city: "Baltimore" }];, but I want cities to be populated by Papa.parse step for each City parsed from my dropboxlink of a csv list of cities in NorthAmerica.

class CitiesMap extends React.Component {
  constructor(props) {
    super(props);
    this.updateData = this.updateData.bind(this);
  }
  componentDidMount() {
    Papa.parse(
      "https://cors-anywhere.herokuapp.com/https://www.dropbox.com/s/5vcoo9r60hgczd1/worldcitiespop_northamerica_nolonglat.csv?dl=1",
      {
        download: true,
        header: true,
        worker: true,
        skipEmptyLines: true,
        step: this.updateData,
        complete: function() {
          console.log("all done");
        }
      }
    );
  }
  updateData(results) {
    cities.push(results.data, ["City"]);
    this.setState({ cities });
  }
  render(props) { 
    let filteredCities = cities.filter(cities => {
      return (
        cities.City.toUpperCase().indexOf(this.props.search.toUpperCase()) !==
        -1
      );
    });
    return (
      <div>
        <div className="Cities">
          {filteredCities.map(City => {
            return (
              <div>
                <WeatherCitySkyMap
                  description={this.description}
                  humidity={this.humidity}
                />
                {JSON.stringify([City])
                  .replace(/[^\w\s]/g, "")
                  .replace(/(city)/g, "")}
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

export default CitiesMap;

"This pattern is found here" link uses UNSAFE_componentWillMount()), instead I try to use componentDidMount() around Papa.parse, but need the Papa.parse results.data to happen before they render like componentWillMount() would have done (or should I use shouldComponentUpdate & forceUpdate() somewhere?). I read best practices is to replace componentWillMount with constructor and super, so should I put Papa.Parse in the constructor? I tried that and got lost. Thanks for reading & your help in advance.

UPDATE after Domino987 answer (so far):

import React from "react";
import WeatherCitySkyMap from "./WeatherCitySkyMap";
import Papa from "papaparse";

import ".././Explore/Cities.css";

class CitiesMap extends React.Component {
  constructor(props) {
    super(props);
    this.updateData = this.updateData.bind(this);
    this.state = { cities: [] };
  }
  componentDidMount() {
    Papa.parse( "https://dl.dropboxusercontent.com/s/k81s5enbamijuke/worldcitiespop_northamerica_nolonglat_few.csv?dl=0",
      {
        download: true,
        header: true,
        worker: true,
        skipEmptyLines: true,
        step: this.updateData,
        complete: function() {
          console.log("all done");
        }
      }
    );
  }
  updateData(results) {
    this.setState(prevState => ({
      cities: [...prevState.cities, results.data.City]
    }));
  }
  render(props) {
    let filteredCities = this.state.cities.filter(cities => {
      return (
        cities.City.toUpperCase().indexOf(this.props.search.toUpperCase()) !==
        -1
      );
    });
    return (
      <div>
        <div className="Cities">
          {filteredCities.map(City => {
            return (
              <div>
                <WeatherCitySkyMap
                  description={this.description}
                  humidity={this.humidity}
                />
                {JSON.stringify([City])
                  .replace(/[^\w\s]/g, "")
                  .replace(/(city)/g, "")}
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

export default CitiesMap;


Answers 1


So there are a few misconceptions of how the component works:

  1. Props are not passed to render: You can access them with this.props.
  2. Local state is null at beginning: in your constructor write this.state = {cities: []}, This will prevent breaking your code if you try to access cities within render.
  3. To access cities in your render and updateData use this.state.cities. This will let you access the current cities.
  4. To update an array within the state write it like this: this.setState(prevState => { cities: [...prevState.cities, results.data.City] });. This will update the state immutable and will keep the previous cities.

componentDidMount is the correct way to implement a server call, side effect or Papa.parse. It will render the component without data first, but as soon as data is present, it will update it. The component will not break, because with point 2 the state will not be null and the render will still work.

I hope these remarks will help you get your code working.

// Edit Since you ask how to implement updateData and render, here is some code:

updateData(results) {
  // This will not work because cities is not defined here (us this.state.cities) and you mutate the data with push
  // cities.push(results.data.city); 
  // I am not sure why you add "City" but that is in your code
  this.setState(prevState => { cities: [...prevState.cities, results.data.City]});
}
render(props) {
  // Filter will check each city in the cities array, so you have to write it like this:
  const filteredCities = this.state.cities.filter(city => city.indexOf(this.props.search.toUpperCase()) !== -1);
}

Happy coding.

Domino987
Domino987
August 19, 2019 20:03 PM

Related Questions


papaparse not parsing full data

Updated February 23, 2019 14:26 PM

Papa Parse with backslash escaping

Updated December 07, 2018 17:26 PM

Remove unwanted columns from CSV file using Papaparse

Updated January 27, 2019 12:26 PM

Move results of papaparse into array

Updated March 08, 2019 20:26 PM

Wait for two or more files to load with Papa Parse

Updated December 20, 2017 09:26 AM