我想做什么:
我想用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调用的问题?
答案 0 :(得分:0)
React基本上采用组件的道具和状态,当这些更改时,它会更新组件(它再次执行渲染功能,然后将其与实际DOM区分开来)。
使用ComponentDidUpdate方法进入生命周期。每次React updates a component都会调用此方法。因此,第一次调用你的数组是空的(你的ajax调用没有返回)。然后你的调用返回,这导致数组被填充。 React更新您的组件,您将获得更新的数据。你看到日志两次的事实很简单,因为根据React,你的组件应该更新:一次是空数组,一次是填充数组中的结果。
要查看您是否实际创建了两个组件,请检查构造函数或ComponentDidMount方法,登录时只应在每个组件的预期创建时调用一次。
总结一下:多次调用ComponentDidUpdate调用没问题。