ReactJS和D3JS:setState

时间:2019-02-22 06:10:38

标签: javascript d3.js

我正在尝试使用reactJS和D3JS(v5)可视化股价图表。

  • 从Alphavantage API中获取数据
  • 框架= ReactJS(说实话,它引入了不必要的复杂性层)
  • D3JS for viz

大致分为三部分:

  1. 全局函数parseData()。将fetch中的数据解析为 d3可以读取的格式。已验证工作正常,但包含在 完整性。
  2. componentDidMount()中进行
  3. class App通话。承诺链:先获取调用,然后依次访问parseData()setState(),最后 drawChart()
  4. drawChart()中的
  5. class App局部函数:包含所有D3逻辑。稍后将被分离成自己的组件。如果我从本地json传递数据(注释掉;下面提供了一些示例行),则有效,但是当我尝试传递数据时不起作用 来自fetch的数据。

到目前为止的代码:全部包含在App.js中,没有子组件:

import React, { Component } from 'react';
import './App.css';
import * as d3 from "d3";
//import testTimeData from "./data/testTimeData"

function parseData(myInput) {
  // processes alpha vantage data into a format for viz
  // output an array of objects, 
  // where each object is {"Date":"yyyy-mm-dd", "a":<float>}
  let newArray = []
  for (var key in myInput) {
      if (myInput.hasOwnProperty(key)) {
          const newRow = Object.assign({"newDate": new Date(key)}, {"Date": key}, myInput[key])
          newArray.push(newRow)
      }
  }
  //console.log(newArray)
  // 2. Generate plotData for d3js
  let newArray2 = []
  for (var i = 0; i < newArray.length; i++) {
    let newRow = Object.assign({"Date": newArray[i]["Date"]}, {"a":parseFloat(newArray[i]["4. close"])})
    newArray2.unshift(newRow)
  }

  return newArray2
}


class App extends Component {
  constructor() {
    super()
    this.state = {
      ticker:"", 
      plotData:[]
    }
    this.drawChart = this.drawChart.bind(this)
  }

  // setState() in componentDidMount()
  // fetch monthly data
  // hardcode ticker = VTSAX for the moment
  // and call this.drawChart()
  componentDidMount() {
    const ticker = "VTSAX"
    const api_key = "EEKL6B77HNZE6EB4"
    fetch("https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol="+ticker+"&apikey="+api_key)
    .then(console.log("fetching..."))
    .then(response => response.json())
    .then(data => parseData(data["Monthly Time Series"]))
    .then(data => console.log(data))
    .then(data =>{this.setState({plotData:data, ticker:ticker})})
    .then(this.drawChart());
  }


  drawChart() {
    const stockPlotData = this.state.plotData
    console.log("stockPlotData.length=", stockPlotData.length)
    var svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 300)

    var margin = {left:50, right:30, top:30, bottom: 30}
    var width = svg.attr("width") - margin.left - margin.right;
    var height = svg.attr("height") - margin.bottom - margin.top;

    var x = d3.scaleTime().rangeRound([0, width]);
    var y = d3.scaleLinear().rangeRound([height, 0]);
    var parseTime = d3.timeParse("%Y-%m-%d");

    x.domain(d3.extent(stockPlotData, function(d) { return parseTime(d.date); }));
    y.domain([0, 
              d3.max(stockPlotData, function(d) { 
                return d.a;
              })]);

    var multiline = function(category) {
      var line = d3.line()
                  .x(function(d) { return x(parseTime(d.date)); })
                  .y(function(d) { return y(d[category]); });
      return line;
    }

    var g = svg.append("g")
        .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

    var categories = ['a'];
    for (let i in categories) {
      var lineFunction = multiline(categories[i]);
      g.append("path")
        .datum(stockPlotData) 
        .attr("class", "line")
        .style("stroke", "blue")
        //.style("stroke", color(i))
        .style("fill", "None")
        .attr("d", lineFunction);
    }

    // append X Axis
    g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%Y-%m-%d")));

    // append Y Axis
    g.append("g")
    .call(d3.axisLeft(y));
  }

  render(){
    return (<div>{this.state.ticker}</div>)
  }
}


export default App;

来自console.log()调用的输出:

    data => console.log(data)的承诺链中的
  • componentDidMount()正确显示提取的数据
  • 但是console.log("stockPlotData.length=", stockPlotData.length)函数中的drawChart()调用返回stockPlotData.length= 0。我打错了this.setState()吗?
  • 该页面在底部的render(){return(...)}调用中正确呈现了“ VTSAX”,指示this.setState正确更新了ticker变量。

一些测试数据行:

[
{"Date":"2016-01-15", "a": 220 },
{"Date":"2016-01-16", "a": 250},
{"Date":"2016-01-17", "a": 130},
{"Date":"2016-01-18", "a": 180},
{"Date":"2016-01-19", "a": 200},
]

1 个答案:

答案 0 :(得分:0)

要阅读的代码很多,但是基于快速浏览,您可能希望在.then内部而不是在promise链之后调用this.drawChart(),因为它会在您的promise兑现之前触发。 / p>