Я использую material-ui
и react-charts-js
для создания страницы, которая извлекается из бэкэнда и отображает данные.
У меня возникли проблемы с пониманием того, как правильно отображать MyGraph
.
Страница содержит два Date Picker
, Toggle
и Raised Button
.
Я хотел бы отобразить во втором Tab
график после того, как данные выбраны и пользователь нажал на кнопку, затем сбросил данные и повторил снова.
Это некоторые попытки, но при этой стратегии MyGraph
отображается правильно, но когда он вызывает this.props.onCreated()
, this.state.buttonClicked
ложно и график скрыт.
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}}/>
);
}
}