我使用material-ui
和react-charts-js
构建一个从后端获取并显示数据的页面。
我在理解如何正确显示MyGraph
时遇到了一些麻烦。
该页面包含两个Date Picker
,一个Toggle
和一个Raised Button
。
在选择数据并且用户点击按钮后,我想在第二个Tab
图表中显示,然后重置数据并重复。
这些是一些尝试,但使用此策略时,MyGraph
已正确显示,但当它调用this.props.onCreated()
时,this.state.buttonClicked
为false且图表已隐藏。
MyCard.js
import React from 'react';
import {Card, Tabs, Tab, FontIcon, DatePicker, Toggle, GridList, GridTile, SelectField, MenuItem, RaisedButton} from 'material-ui/';
import MyGraph from './MyGraph';
const styles = {
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
margin: '0 auto'
},
gridList: {
width: 200,
height: 500,
overflowY: 'auto',
},
};
export default class MyCard extends React.Component {
constructor(props){
super(props)
this.state = {
queryNumber: 1,
startDate: null,
endDate: null,
sameRegion: true,
buttonDisabled: true,
buttonClicked: false
}
}
handleQueryNumberChange = (event, index, value) => {
this.setState({queryNumber: value});
}
check(){
if (this.state.startDate && this.state.endDate) {
this.setState({buttonDisabled: false})
}
}
handleStartDateChange = (event, date) => {
this.setState({
startDate: date,
}, this.check);
};
handleEndDateChange = (event, date) => {
this.setState({
endDate: date,
}, this.check);
};
handleSameRegionChange = (event, isInputChecked) =>{
this.setState({sameRegion: isInputChecked});
}
handleClick = (event) =>{
this.setState({buttonClicked: true})
}
resetForm = () =>{
this.setState({buttonClicked: false, startDate: null, endDate: null, buttonDisabled: true})
}
render() {
return (
<Card>
<Tabs>
<Tab icon={<FontIcon className="material-icons" >date_range</FontIcon>} label="Pick">
<div style={styles.root}>
<GridList
cols={1}
cellHeight={100}
padding={1}
style={styles.gridList}
>
<GridTile>
<SelectField
floatingLabelText="Query"
value={this.state.queryNumber}
onChange={this.handleQueryNumberChange}
>
<MenuItem value={1} primaryText="Date" />
<MenuItem value={2} primaryText="Query2" />
<MenuItem value={3} primaryText="Query3" />
<MenuItem value={4} primaryText="Query4" />
<MenuItem value={5} primaryText="Query5" />
</SelectField>
</GridTile>
<GridTile>
<DatePicker hintText="Select start date" value={this.state.startDate} onChange={this.handleStartDateChange}/>
</GridTile>
<GridTile>
<DatePicker hintText="Select end date" value={this.state.endDate} onChange={this.handleEndDateChange}/>
</GridTile>
<GridTile>
<Toggle label="Same Region" defaultToggled={true} onToggle={this.handleSameRegionChange}/>
</GridTile>
<GridTile>
<RaisedButton label="Send" secondary={true} disabled={this.state.buttonDisabled} onClick={this.handleClick}/>
</GridTile>
</GridList>
</div>
</Tab>
<Tab icon={<FontIcon className="material-icons" >pie_chart</FontIcon>} label="Graph">
<div>
{this.state.buttonClicked && <MyGraph values={this.state} onCreated={this.resetForm}/>}
</div>
</Tab>
</Tabs>
</Card>
);
}
}
MyGraph.js
import React from 'react';
import {Pie} from 'react-chartjs-2';
import moment from 'moment'
export default class MyGraph extends React.Component {
constructor(props) {
super(props);
this.state = {
data: props,
labels: [],
datasets: [{
data: [],
backgroundColor: [
'#d50000',
'#2962ff',
'#00c853',
'#ffab00'
],
hoverBackgroundColor: [
'#ff5252',
'#448aff',
'#69f0ae',
'#ffd740'
]
}]
}
}
call(){
this.callApi()
.then(res => {
console.log(res)
let datasetsModified = this.state.datasets;
let labelsModified = this.state.labels;
datasetsModified[0].data.length = 0;
labelsModified.length = 0;
for(let resource of res){
datasetsModified[0].data.push(resource.avg)
labelsModified.push(resource._id)
}
this.setState({
labels: labelsModified,
datasets: datasetsModified,
})
})
.then(() =>{
this.props.onCreated()
})
.catch(err => console.log(err))
}
async callApi(){
var query = 'http://localhost:3100/api/pings/query/avgInDay?start='+moment(this.state.data.values.startDate).format('YYYY-MM-DD')+'&end='+moment(this.state.data.values.endDate).format('YYYY-MM-DD')+'&sameRegion='+((this.state.data.values.sameRegion === true) ? 0 : 1)
const response = await fetch(query);
const body = await response.json();
return body;
}
componentDidMount(){
this.call()
}
componentWillReceiveProps(nextProps) { // Successives rendering
console.log('will')
this.setState({data: nextProps}, this.call())
}
render() {
return (
<Pie data={this.state} width={500} height={500} options={{maintainAspectRatio: false}}/>
);
}
}
有人能说明这样做的正确方法吗?
提前致谢:)
编辑1:我试图解除状态,它正在做我想要的事情,但MyGraph在点击之前被调用每一次修改;这样可以吗?
最后,我的标签和数据会更新,但不会更新
MyCard.js
import React from 'react';
import {Card, Tabs, Tab, FontIcon, DatePicker, Toggle, GridList, GridTile, SelectField, MenuItem, RaisedButton} from 'material-ui/';
import MyGraph from './MyGraph';
import moment from "moment/moment";
const styles = {
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
margin: '0 auto'
},
gridList: {
width: 200,
height: 500,
overflowY: 'auto',
},
};
export default class MyCard extends React.Component {
constructor(props){
super(props)
this.state = {
queryNumber: 1,
startDate: null,
endDate: null,
sameRegion: true,
buttonDisabled: true,
buttonClicked: false,
graphData: {
data: props,
labels: [],
datasets: [{
data: [],
backgroundColor: [
'#d50000',
'#2962ff',
'#00c853',
'#ffab00'
],
hoverBackgroundColor: [
'#ff5252',
'#448aff',
'#69f0ae',
'#ffd740'
]
}]
}
}
}
handleQueryNumberChange = (event, index, value) => {
this.setState({queryNumber: value});
}
check(){
if (this.state.startDate && this.state.endDate) {
this.setState({buttonDisabled: false})
}
}
handleStartDateChange = (event, date) => {
this.setState({
startDate: date,
}, this.check);
};
handleEndDateChange = (event, date) => {
this.setState({
endDate: date,
}, this.check);
};
handleSameRegionChange = (event, isInputChecked) =>{
this.setState({sameRegion: isInputChecked});
}
handleClick = (event) =>{
this.callApi()
.then(res => {
console.log(res)
let graphDataModified = this.state.graphData;
let datasetsModified = graphDataModified.datasets;
let labelsModified = graphDataModified.labels;
datasetsModified[0].data.length = 0;
labelsModified.length = 0;
for(let resource of res){
datasetsModified[0].data.push(resource.avg)
labelsModified.push(resource._id)
}
this.setState({graphData: graphDataModified, buttonClicked: true})
})
.then(() =>{
this.resetForm()
})
.catch(err => console.log(err))
}
async callApi(){
var query = 'http://localhost:3100/api/pings/query/avgInDay?start='+moment(this.state.startDate).format('YYYY-MM-DD')+'&end='+moment(this.state.endDate).format('YYYY-MM-DD')+'&sameRegion='+((this.state.sameRegion === true) ? 0 : 1)
const response = await fetch(query);
const body = await response.json();
return body;
}
resetForm = () =>{
this.setState({startDate: null, endDate: null, buttonDisabled: true})
}
render() {
return (
<Card>
<Tabs>
<Tab icon={<FontIcon className="material-icons" >date_range</FontIcon>} label="Pick">
<div style={styles.root}>
<GridList
cols={1}
cellHeight={100}
padding={1}
style={styles.gridList}
>
<GridTile>
<SelectField
floatingLabelText="Query"
value={this.state.queryNumber}
onChange={this.handleQueryNumberChange}
>
<MenuItem value={1} primaryText="Date" />
<MenuItem value={2} primaryText="Query2" />
<MenuItem value={3} primaryText="Query3" />
<MenuItem value={4} primaryText="Query4" />
<MenuItem value={5} primaryText="Query5" />
</SelectField>
</GridTile>
<GridTile>
<DatePicker hintText="Select start date" value={this.state.startDate} onChange={this.handleStartDateChange}/>
</GridTile>
<GridTile>
<DatePicker hintText="Select end date" value={this.state.endDate} onChange={this.handleEndDateChange}/>
</GridTile>
<GridTile>
<Toggle label="Same Region" defaultToggled={true} onToggle={this.handleSameRegionChange}/>
</GridTile>
<GridTile>
<RaisedButton label="Send" secondary={true} disabled={this.state.buttonDisabled} onClick={this.handleClick}/>
</GridTile>
</GridList>
</div>
</Tab>
<Tab icon={<FontIcon className="material-icons" >pie_chart</FontIcon>} label="Graph">
<div>
{ this.state.buttonClicked ? <MyGraph data={this.state.graphData}/> : null }
</div>
</Tab>
</Tabs>
</Card>
);
}
}
MyGraph.js
import React from 'react';
import {Pie} from 'react-chartjs-2';
export default class MyGraph extends React.Component {
render() {
console.log(this.props.data)
return (
<Pie data={this.props.data} width={500} height={500} options={{maintainAspectRatio: false}}/>
);
}
}