首页 > 解决方案 > 使用 d3.csv 加载数据后无法更新 React 中的状态

问题描述

我正在使用 React 使用 D3v4 构建力模拟。但是,如果我的对象数组已经处于我的状态(在本例中为节点),并且如果我尝试从 csv 文件中读取它并使用 setState 它不起作用,我只能让它工作。同样在我的 Force.js 文件中,当我尝试为 ForceX 设置 this.props.width / 2 为 ForceY 设置 this.props.height / 2 时它不起作用,我必须直接为 ForceX 输入 400 ForceY 需要 250 美元才能正常工作。

如果有人能指出我正确的方向,那就太好了!

不使用 d3.csv 的版本:

应用程序.js

import React, { Component } from "react";
import * as d3 from "d3";
import Force from "./Force";


class App extends Component {


      state = {
        width: 800,
        height: 500,
        nodes: [
        {
          "ID": 1,
          "name": "Chlamydoselachus africana",
          "url": "https://en.wikipedia.org/wiki/Chlamydoselachus_africana",
          "common_name": "African frilled shark",
          "size": 117,
          "family": "Chlamydoselachidae",
          "family_common": "Frilled Sharks",
          "min_depth": 300,
          "max_depth": 1400,
          "IUCN": "NA",
          "CITES": 0,
          "baum": "",
          "family_grouped": "Frilled Sharks"
        },
        {
          "ID": 2,
          "name": "Chlamydoselachus anguineus",
          "url": "https://en.wikipedia.org/wiki/Chlamydoselachus_anguineus",
          "common_name": "Frilled shark",
          "size": 150,
          "family": "Chlamydoselachidae",
          "family_common": "Frilled Sharks",
          "min_depth": 0,
          "max_depth": 1570,
          "IUCN": "LC",
          "CITES": 0,
          "baum": "",
          "family_grouped": "Frilled Sharks"
        },
        {
          "ID": 3,
          "name": "Heptranchias perlo",
          "url": "https://en.wikipedia.org/wiki/Heptranchias_perlo",
          "common_name": "Sharp-nose sevengill shark",
          "size": 140,
          "family": "Hexanchidae",
          "family_common": "Cow Sharks",
          "min_depth": 0,
          "max_depth": 1000,
          "IUCN": "NT",
          "CITES": 0,
          "baum": "",
          "family_grouped": "Cow Sharks"
        },
        {
          "ID": 4,
          "name": "Hexanchus griseus",
          "url": "https://en.wikipedia.org/wiki/Hexanchus_griseus",
          "common_name": "Blunt-nose sixgill shark",
          "size": 790,
          "family": "Hexanchidae",
          "family_common": "Cow Sharks"
        },
        {
          "ID": 5,
          "name": "Hexanchus nakamurai",
          "url": "https://en.wikipedia.org/wiki/Hexanchus_nakamurai",
          "common_name": "Bigeyed sixgill shark",
          "size": 180,
          "family": "Hexanchidae",
          "family_common": "Cow Sharks"
        },
        {
          "ID": 6,
          "name": "Hexanchus vitulus",
          "url": "https://en.wikipedia.org/wiki/Hexanchus_vitulus",
          "common_name": "Atlantic sixgill shark",
          "size": 220,
          "family": "Hexanchidae",
          "family_common": "Cow Sharks"
        },
        {
          "ID": 7,
          "name": "Notorynchus cepedianus",
          "url": "https://en.wikipedia.org/wiki/Notorynchus_cepedianus",
          "common_name": "Broad-nose sevengill shark",
          "size": 300,
          "family": "Hexanchidae",
          "family_common": "Cow Sharks"
        },
        {
          "ID": 8,
          "name": "Centrophorus atromarginatus",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_atromarginatus",
          "common_name": "Dwarf gulper shark",
          "size": 87,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 9,
          "name": "Centrophorus granulosus",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_granulosus",
          "common_name": "Gulper shark",
          "size": 100,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 10,
          "name": "Centrophorus harrissoni",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_harrissoni",
          "common_name": "Dumb gulper shark",
          "size": 110,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 11,
          "name": "Centrophorus moluccensis",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_moluccensis",
          "common_name": "Small-fin gulper shark",
          "size": 98,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 12,
          "name": "Centrophorus seychellorum",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_seychellorum",
          "common_name": "Seychelles gulper shark",
          "size": 80,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 13,
          "name": "Centrophorus squamosus",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_squamosus",
          "common_name": "Leaf-scale gulper shark",
          "size": 158,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 14,
          "name": "Centrophorus tessellatus",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_tessellatus",
          "common_name": "Mosaic gulper shark",
          "size": 89,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        },
        {
          "ID": 15,
          "name": "Centrophorus uyato",
          "url": "https://en.wikipedia.org/wiki/Centrophorus_uyato",
          "common_name": "Little gulper shark",
          "size": 110,
          "family": "Centrophoridae",
          "family_common": "Gulper Sharks"
        }],
        margin:{left:10,top:10,right:10,bottom:10}
      };


        render() {
          return (
            <Force width={this.state.width} height={this.state.height} data={this.state.nodes} />
          );
        }
      }


export default App;

Force.js

import React from "react";
import * as d3 from "d3";
import _ from "lodash";

class Force extends React.Component {


  constructor(props){
    super(props);

    var forceSim;

  }
      componentDidMount() {

       var radiusScale = d3.scaleSqrt()
           .range([0,0.7]);

        this.forceSim = d3.forceSimulation(this.props.data)
      .force('x', d3.forceX(function(d) {
               return 400
           }).strength(0.03))
           .force('y', d3.forceY(function(d) {
               return 250
           }).strength((0.03)))
           .force('collide', d3.forceCollide(function(d) {
               return radiusScale(+d.size)
           })).velocityDecay(0.1).alphaDecay(0.01);

      this.forceSim.on('tick', () => this.setState({nodes: this.props.data}));

      }

      componentWillUnmount() {
          this.forceSim.stop();
        }

            render() {
            var colorScale = d3.scaleOrdinal()
                .range(['#450303', '#6e0505', '#951f1f'
                ]);
                var radiusScale = d3.scaleSqrt()
                    .range([0.5,0.9]);
            return (
                <svg width={this.props.width} height={this.props.height}>
                {this.props.data.map((node, index) =>(
                    <circle r={radiusScale(node.size)} cx={node.x} cy={node.y} fill={colorScale(node.family)} key={index}/>
                ))}
              </svg>
            );
          }
        }


export default Force;

使用 d3.csv 不起作用的版本,但我想让它工作:

应用程序.js

import React, { Component } from "react";
import * as d3 from "d3";
import Force from "./Force";
import data from './data.csv';

class App extends Component {

      state = {
        width: 800,
        height: 500,
        nodes: [],
        margin:{left:10,top:10,right:10,bottom:10}
      };

      componentDidMount() {

       d3.csv(data).then(function(data) {
         console.log(data)
         this.setState(prevState =>({
          nodes: data
         }))
       }).catch(function(err) {
           throw err;
       })
    }


        render() {
          return (
            <Force width={this.state.width} height={this.state.height} data={this.state.nodes} />
          );
        }
      }


export default App;

Force.js

this.forceSim = d3.forceSimulation(this.props.data)
          .force('x', d3.forceX(function(d) {
                   return (this.props.width)/2  ////HERE
               }).strength(0.03))
               .force('y', d3.forceY(function(d) {
                   return (this.props.height)/2  ////HERE
               }).strength((0.03)))
               .force('collide', d3.forceCollide(function(d) {
                   return radiusScale(+d.size)
               })).velocityDecay(0.1).alphaDecay(0.01);

这是 csv 文件数据:

ID,name,url,common_name,size,family,family_common 1,Chlamydoselachusafricana, https://en.wikipedia.org/wiki/Chlamydoselachus_africana,African frilled Shark ,117,Chlamydoselachidae,Frilled Sharks 2,Chlamydoselachus anguineus, https:// /en.wikipedia.org/wiki/Chlamydoselachus_anguineus ,褶边鲨,150,Chlamydoselachidae,褶边鲨 3,Heptranchias perlo, https://en.wikipedia.org/wiki/Heptranchias_perlo ,尖鼻七鳃鲨,140,​​Hexanchidae,牛鲨鱼 4,Hexanchus griseus,https: //en.wikipedia.org/wiki/Hexanchus_griseus,钝鼻六鳃鲨,790,Hexanchidae,牛鲨 5,Hexanchus nakamurai,https ://en.wikipedia.org/wiki/Hexanchus_nakamurai ,大眼六鳃鲨,180,Hexanchidae,Cow Sharks 6,Hexanchus vitulus,https://en.wikipedia.org/wiki/Hexanchus_vitulus ,大西洋六鳃鲨,220,六鳃鲨科,牛鲨 7,Notorynchus cepedianus, https://en.wikipedia.org/wiki/Notorynchus_cepedianus ,宽鼻七鳃鲨,300 ,Hexanchidae,Cow Sharks 8,Centrophorus atromarginatus, https://en.wikipedia.org/wiki/Centrophorus_atromarginatus ,侏儒鲨,87,Centrophoridae,Gulper Sharks 9,Centrophorus granulosus, https://en.wikipedia.org/wiki /Centrophorus_granulosus, Gulper Sharks,100,Centrophoridae,Gulper Sharks 10,Centrophorus harrissoni, https://en.wikipedia.org/wiki/Centrophorus_harrissoni,Dumb gulper Shark,110,Centrophoridae,Gulper Sharks 11,Centrophorus moluccensis,https://en.wikipedia.org/wiki/Centrophorus_moluccensis,Small-fin gulper shark,98,Centrophoridae,Gulper Sharks 12,Centrophorus seychhellorum, https://en.wikipedia.org/wiki/Centrophorus_seychhellorum,Seychelles gulper Sharks ,80 ,Centrophoridae,Gulper Sharks 13,Centrophorus squamosus, https://en.wikipedia.org/wiki/Centrophorus_squamosus ,叶鳞鲨,158,Centrophoridae,Gulper Sharks 14,Centrophorus tessellatus, https://en.wikipedia.org /wiki/Centrophorus_tessellatus,Mosaic gulper shark,89,Centrophoridae,Gulper Sharks

标签: reactjscsvd3.js

解决方案


错误在于匿名函数和this. 这是对工作原理的很好解释thishttps ://stackoverflow.com/a/3127440/5122581


在您的代码中:

d3.csv(data).then(function(data) {
  console.log(data)
  this.setState(prevState =>({
  nodes: data
  }))
}).catch(function(err) {
  throw err;
})

您使用匿名函数将 promise 传递给 then 回调。此函数没有this您期望的 -binding。有三种解决方案:

箭头功能:

d3.cvs(data).then((data) => {
  this.setState({ nodes: data });
});

this在外部范围内创建变量:

const self = this;

d3.cvs(data).then(function(data) {
  self.setState({ nodes: data });
});

绑定函数:

function callback(data) {
  this.setState({ nodes: data });
}

d3.csv(data).then(callback.bind(this));

由于您已经在使用箭头函数,我认为它们是最简洁和优雅的解决方案


推荐阅读