简体   繁体   中英

Using D3 or Papa to Read CSV in React App

I'm trying to figure out how to read a local file from a local react app. I created my react app with npx create-react-app my_app and am running it with npm start . Here's a minimal index.jsx file to induce the problem.

import React from 'react';
import ReactDOM from "react-dom";
import * as d3 from 'd3';

class Page extends React.Component {
  render() {
    var csvFilePath = "./data/my_data.csv";
    console.log("min/index.jsx rows:");
    var csvFile = d3.csv(csvFilePath).then(function(row) {
      console.log(row);
    });

    console.log("min/index.jsx csvFile:");
    console.log("csvfile: " + csvFile);
    console.log(csvFile);
    // console.log("type: " + type(csvFile));
    console.log("min/index.jsx csvFile end");

    return (
      <div className="page-holder"></div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);

Which produces console logs like so:

index.jsx:8 min/index.jsx rows:
index.jsx:13 min/index.jsx csvFile:
index.jsx:14 csvfile: [object Promise]
index.jsx:15 Promise
index.jsx:17 min/index.jsx csvFile end
index.jsx:10 (42) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, columns: Array(1)]0: {<!DOCTYPE html>: "<html lang="en">"}1: {<!DOCTYPE html>: "  <head>"}2: {<!DOCTYPE html>: "    <meta charset="utf-8" />"}3: {<!DOCTYPE html>: "    <link rel="icon" href="/favicon.ico" />"}4: {<!DOCTYPE html>: "    <meta name="viewport" content="width=device-width"}5: {<!DOCTYPE html>: "    <meta name="theme-color" content="#000000" />"}6: {<!DOCTYPE html>: "    <meta"}7: {<!DOCTYPE html>: "      name="description""}8: {<!DOCTYPE html>: "      content="Web site created using create-react-app""}9: {<!DOCTYPE html>: "    />"}10: {<!DOCTYPE html>: "    <link rel="apple-touch-icon" href="/logo192.png" />"}11: {<!DOCTYPE html>: "    <!--"}12: {<!DOCTYPE html>: "      manifest.json provides metadata used when your web app is installed on a"}13: {<!DOCTYPE html>: "      user's mobile device or desktop. See https:/…ers.google.com/web/fundamentals/web-app-manifest/"}14: {<!DOCTYPE html>: "    -->"}15: {<!DOCTYPE html>: "    <link rel="manifest" href="/manifest.json" />"}16: {<!DOCTYPE html>: "    <!--"}17: {<!DOCTYPE html>: "      Notice the use of  in the tags above."}18: {<!DOCTYPE html>: "      It will be replaced with the URL of the `public` folder during the build."}19: {<!DOCTYPE html>: "      Only files inside the `public` folder can be referenced from the HTML."}20: {<!DOCTYPE html>: ""}21: {<!DOCTYPE html>: "      Unlike "/favicon.ico" or "favicon.ico""}22: {<!DOCTYPE html>: "      work correctly both with client-side routing and a non-root public URL."}23: {<!DOCTYPE html>: "      Learn how to configure a non-root public URL by running `npm run build`."}24: {<!DOCTYPE html>: "    -->"}25: {<!DOCTYPE html>: "    <title>React App</title>"}26: {<!DOCTYPE html>: "  </head>"}27: {<!DOCTYPE html>: "  <body>"}28: {<!DOCTYPE html>: "    <noscript>You need to enable JavaScript to run this app.</noscript>"}29: {<!DOCTYPE html>: "    <div id="root"></div>"}30: {<!DOCTYPE html>: "    <!--"}31: {<!DOCTYPE html>: "      This HTML file is a template."}32: {<!DOCTYPE html>: "      If you open it directly in the browser"}33: {<!DOCTYPE html>: ""}34: {<!DOCTYPE html>: "      You can add webfonts"}35: {<!DOCTYPE html>: "      The build step will place the bundled scripts into the <body> tag."}36: {<!DOCTYPE html>: ""}37: {<!DOCTYPE html>: "      To begin the development"}38: {<!DOCTYPE html>: "      To create a production bundle"}39: {<!DOCTYPE html>: "    -->"}40: {<!DOCTYPE html>: "  <script src="/static/js/bundle.js"></script><scr…t src="/static/js/main.chunk.js"></script></body>"}41: {<!DOCTYPE html>: "</html>"}columns: ["<!DOCTYPE html>"]length: 42__proto__: Array(0)
DevTools failed to parse SourceMap: chrome-extension://cfhdojbkjhnklbpkdaibdccddilifddb/include.preload.js.map
DevTools failed to parse SourceMap: chrome-extension://ekhagklcjbdpajgpjgmbionohlpdbjgc/browser-polyfill.js.map
DevTools failed to parse SourceMap: chrome-extension://hdokiejnpimakedhajhdlcegeplioahd/sourcemaps/onloadwff.js.map

and the 42 objects from index.jsx:10 appear to be create-react-app's default index.html rather than my data! They begin:

<html lang=\"en\">
  <head>
    <meta charset=\"utf-8\" />
    <link rel=\"icon\" href=\"/favicon.ico\" />
    <meta name=\"viewport\" content=\"width=device-width
    <meta name=\"theme-color\" content=\"#000000\" />
    <meta
      name=\"description\"
      content=\"Web site created using create-react-app\"
    />
    ...

I'm trying to understand what's going on here. Is node.js acting as a local file server and spitting back its own index.html in response to my d3.csv(...) read? If so, what's the idiomatic best way to read this file? If not, same question.

Thanks for your help!

d3.csv retrieves the CSV file asynchronously.

The whole code processing the CSV file should therefore be enclosed inside .then .

Adapted code:

class Page extends React.Component {
  render() {
    var csvFilePath = "./data/my_data.csv";
    console.log("min/index.jsx rows:");
    d3.csv(csvFilePath).then(function(csvFile) {
      console.log("min/index.jsx csvFile:");
      console.log("csvfile: " + csvFile);
      console.log(csvFile);
      // console.log("type: " + type(csvFile));
      console.log("min/index.jsx csvFile end");

      return (
        <div className="page-holder"></div>
      );
    });

  }
}

Alright, I think I've cracked it.

First I tried importing my data file:

import importedCsvData from './data/my_data.csv';
console.log("Imported Csv Data:");
console.log(importedCsvData);

This yielded logs:

Imported Csv Data: 
/static/media/my_data.6180a709.csv

It seems that node.js wants to serve my local file as static media, and I need to use the import to get the address from which my own node.js server wants to serve it. (It's worth noting that the extra string, '6180a709', doesn't vary from run to run. It seems to be a hash, not a random string).

With this knowledge in tow, I was able to write this component:

import importedCsvData from './data/my_data.csv';

class Page extends React.Component {
  render() {
    var csvFilePath = importedCsvData;
    fetch(csvFilePath)
      .then(rs => rs.text())
      .then(text => {
        console.log('text:');
        console.log(text);
      });

    return null;
  }
}

Which finally read my file as a string into text variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM