反应组件调用了两次(AJAX调用异步)

React component called twice (AJAX call async)

本文关键字:调用 两次 AJAX 异步 组件      更新时间:2023-09-26

我想做什么:

我想用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(data) 首先返回一个空数组,然后返回具有正确值的数组。奇怪的是,什么都没有创建,但即使创建了它,我的组件 Pie 也被调用了两次。

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

非常感谢,我发现了 React.js,很多 Basic 的概念对我来说是未知的。

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

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

React 基本上获取组件的 props 和状态,当这些更改时,它会更新组件(它会再次执行渲染函数,然后将其与您的实际 DOM 进行比较)。

您可以使用 ComponentDidUpdate 方法进入生命周期。每次 React 更新组件时都会调用它。因此,第一次调用数组时,数组为空(ajax 调用尚未返回)。然后您的调用返回,这会导致数组被填充。React 会更新你的组件,你会得到更新的数据。你看到日志两次的事实仅仅是因为,根据 React 的说法,你的组件应该更新:一次是空数组,一次是填充数组中的结果。

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

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