React组件调用两次(AJAX调用异步)

时间:2016-02-19 09:13:13

标签: javascript jquery ajax reactjs

我想做什么:

我想用javascript库d3.js创建一个饼图。我通过AJAX调用从我的服务器获取数据,然后用它创建我的饼图。

我做了什么:

为此我创建了2个react组件:一个实现ajax调用并将其状态传递给另一个组件,该组件创建带有props中数据的饼图。

第一部分:

import React from 'react';
import Pie from './pie.jsx';

class RingChart extends React.Component {
  loadPieChart() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: (data) => {
        let d3data = Object.keys(data)
          .filter(key => key!= 'pourcentage')
          .map(key => { return {name: key, value: data[key]} });
        this.setState({dataPie: d3data, percent: data['pourcentage']});
      },
      error: (xhr, status, err) => {
        console.error(this.props.url, status, err.toString());
      }
    });
  }

  constructor(props) {
    super(props);
    this.state = {dataPie: [], percent: 0};
  }

  componentDidMount() {
    this.loadPieChart();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  }

  render() {
    return (
    <div className="chart">
      <Pie size="400" data={this.state.dataPie} percent={this.state.percent}></Pie>
    </div>
    );
  }
}

export default RingChart;

这是我创建饼图的第二个组件:

import React from 'react';

class Pie extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidUpdate() {
    let size = this.props.size;
    const data = this.props.data;
    let percent = this.props.percent;

    console.log(data);

    var margin = {top: 20, right: 20, bottom: 20, left: 20};
    let width = size - margin.left - margin.right;
    let height = width - margin.top - margin.bottom;

    var chart = d3.select(".ring")
                    .append('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                   .append("g")
                    .attr("transform", "translate(" + ((width/2)+margin.left) + "," + ((height/2)+margin.top) + ")");

    var radius = Math.min(width, height) / 2;

    var color = d3.scale.ordinal()
        .range(["#313F46", "#4DD0E1"]);

    var arc = d3.svg.arc()
        .outerRadius(radius)
        .innerRadius(radius - 20);

    var pie = d3.layout.pie()
        .sort(null)
        .startAngle(1.1*Math.PI)
        .endAngle(3.1*Math.PI)
        .value(function(d) { return d.value; });


    var g = chart.selectAll(".arc")
      .data(pie(data))
      .enter().append("g")
      .attr("className", "arc");
      function tweenPie(b) {
        var i = d3.interpolate({startAngle: 1.1*Math.PI, endAngle: 1.1*Math.PI}, b);
        return function(t) { return arc(i(t)); };
      }
    g.append("path")
        .attr("fill", function(d, i) { return color(i); })
      .transition()
        .ease("exp")
        .duration(600)
        .attrTween("d", tweenPie);

    g.append("text")
          .attr("dy", ".35em")
          .style("text-anchor", "middle")
          .style("color", "#263238")
          .style("font-size", "55px")
          .attr("className", "text-pie")
          .text(function(d) { return percent+'%'; });

  }

  render() {
    return (<div className="ring" style={{textAlign:'center'}}></div>)
  }
}

export default Pie;

我的问题:

没有创建...我的第二个组件中的console.log(数据)首先返回一个空数组,其次返回具有正确值的数组。奇怪的是没有创建任何东西,但即使它被创建,我的组件Pie也会被调用两次。

如何只调用一次我的组件? 为什么我的组件没有创建? 我怎么能这样做,当我的服务器上出现新值时,我的饼图会自动更新?

非常感谢,我发现了react.js,很多基本概念对我来说都是未知的。

编辑:好了,现在我的组件已创建,我忘记了&#34; .ring&#34;在我的行中:var chart = d3.select("ring") -_-。

但正如我之前所说,现在创建了两个组件(一个空,一个正确)。有时我有两个组件正确创建。这取决于AJAX调用...如何解决异步AJAX调用的问题?

1 个答案:

答案 0 :(得分:0)

React基本上采用组件的道具和状态,当这些更改时,它会更新组件(它再次执行渲染功能,然后将其与实际DOM区分开来)。

使用ComponentDidUpdate方法进入生命周期。每次React updates a component都会调用此方法。因此,第一次调用你的数组是空的(你的ajax调用没有返回)。然后你的调用返回,这导致数组被填充。 React更新您的组件,您将获得更新的数据。你看到日志两次的事实很简单,因为根据React,你的组件应该更新:一次是空数组,一次是填充数组中的结果。

要查看您是否实际创建了两个组件,请检查构造函数或ComponentDidMount方法,登录时只应在每个组件的预期创建时调用一次。

总结一下:多次调用ComponentDidUpdate调用没问题。