我正在使用 react-vis 制作折线图。我有一个名为 RoomUtilisation 的父组件和一个名为 ChartGridLine 的子组件。父级获取数据(当前使用模拟数据),然后通过道具将其传递给子级。但是,不知何故,图表仅在我多次更改下拉列表时才会呈现。子组件有时也会使用一组错误的数据,例如选择的 A 类,但使用 B 类的数据。
我尝试调试,似乎 nextProps 和 prevState 在某些情况下是相同的。请帮忙!
var dataArrayA = [];
var dataArrayB = [];
for (var item in sampleDataWeek) {
dataArrayA.push([
sampleDataWeek[item].week,
sampleDataWeek[item].occupancy,
sampleDataWeek[item].capacity
]);
}
for (var item in sampleDataWeekB) {
dataArrayB.push([
sampleDataWeekB[item].week,
sampleDataWeekB[item].occupancy,
sampleDataWeekB[item].capacity
]);
}
class RoomUltilisation extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
loading: true,
selectedClass: "LectureA",
selectedCourse: "COMP9517",
counter: 0 //dummy prop
};
this.classOptions = [
{ value: 0, label: "LectureA" },
{ value: 1, label: "LectureB" }
];
this.courseOptions = [
{ value: 0, label: "COMP9517" },
{ value: 1, label: "ARTS2663" }
];
this.handleChange = this.handleChange.bind(this);
this.addData = this.addData.bind(this);
}
componentDidMount() {
if (this.state.selectedClass === "LectureA") {
this.setState({
data: dataArrayA
});
}
this.setState({
loading: false
});
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
if (this.state.selectedClass === "LectureA") {
this.setState({
data: dataArrayA
});
} else if (this.state.selectedClass === "LectureB") {
this.setState({
data: dataArrayB
});
}
};
render() {
const { loading } = this.state;
if (loading) {
return (
<React.Fragment>
<NavBar />
<SideBar />
<div id="page-wrap">
<h1 style={{ padding: 20 }}>Class Attendance</h1>
<div>Loading Chart ....</div>
</div>
</React.Fragment>
);
}
return (
<React.Fragment>
<NavBar />
<SideBar />
<div id="page-wrap">
<h1 style={{ padding: 20 }}>Class Attendance</h1>
<label htmlFor="course" style={this.textAreaStyle}>
Select course
</label>
<select
id="selectedCourse"
value={this.state.selectedCourse ? this.state.selectedCourse : ""}
onChange={this.handleChange}
>
{this.courseOptions.map((e, key) => {
return (
<option key={key} value={e.label}>
{e.label}
</option>
);
})}
</select>
<label htmlFor="class" style={this.textAreaStyle}>
Select class
</label>
<select
id="selectedClass"
value={this.state.selectedClass ? this.state.selectedClass : ""}
onChange={this.handleChange}
>
{this.classOptions.map((e, key) => {
return (
<option key={key} value={e.label}>
{e.label}
</option>
);
})}
</select>
<div id="chart-wrap">
<ChartGridline
data={this.state.data}
// key={++this.state.counter}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default RoomUltilisation;
class ChartGridline extends Component {
constructor(props) {
super(props);
this.state = {
highlightSeries: null,
highlightTip: null,
receivedData: null,
loading: true,
data: null,
value: null //value of mark?
};
this.translatedArray = [];
this.debouncedSetState = debounce(newState => this.setState(newState), 40);
this._rememberValue = this._rememberValue.bind(this);
this._forgetValue = this._forgetValue.bind(this);
}
async componentDidMount() {
await this.translateSeries(this.props.data);
this.setState({ loading: false });
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.data !== prevState.data) {
return {
data: nextProps.data
};
}
// Return null if the state hasn't changed
return null;
}
async componentDidUpdate(prevProps, prevState, snapshot) {
if (JSON.stringify(this.props) !== JSON.stringify(prevProps.data)) {
console.log("state has changed!");
await this.translateSeries(this.props.data);
}
// if (snapshot.loading) {
// console.log("computing....!");
// }
}
async translateSeries(data) {
this.translatedArray = [1].map(i =>
data.map(input => ({
x: new Date(input[0]),
y: input[1],
capacity: input[2]
}))
);
console.log("translated function: " + JSON.stringify(this.translatedArray));
}
_rememberValue(value) {
this.setState({ value });
}
_forgetValue() {
this.setState({ value: null });
}
axisProps = {
tickSizeInner: 0,
style: { line: { stroke: "#939393", strokeWidth: "1px" } }
};
hintStyle = {
fontSize: 14,
color: "black",
background: "#faffe6",
borderRadius: "5px",
border: "3px solid #fff"
};
render() {
const { highlightSeries, loading, value } = this.state;
console.log("render method is called");
if (loading) {
return (
<React.Fragment>
<div>loading...</div>
</React.Fragment>
);
}
return (
<div>
<DiscreteColorLegend
// items={["Attendance", "Enrolment"]}
items={["Attendance"]}
orientation="horizontal"
// style={{ position: "absolute", textAlign: "left", right: "25%" }}
strokeWidth="3px"
/>
<XYPlot
xDomain={[0, 20]}
key="1"
width={600}
height={600}
onMouseLeave={() => this.setState({ highlightTip: null })}
>
<XAxis
title="semester week"
{...this.axisProps}
tickFormat={String}
/>
<YAxis
title="occupancy"
{...this.axisProps}
// tickFormat={d => d + "%"}
tickFormat={d => d}
/>
{this.translatedArray.map((d, i) => (
<LineMarkSeries
key={i}
size={3}
data={d}
onValueMouseOver={this._rememberValue}
onValueMouseOut={this._forgetValue}
onSeriesMouseOver={() =>
this.debouncedSetState({ highlightSeries: d })
}
onSeriesMouseOut={() =>
this.debouncedSetState({
highlightSeries: null
})
}
stroke={d === highlightSeries ? "black" : bgColors.Blue}
/>
))}
{console.log("this.translatedArray: " + this.translatedArray)}
{value ? (
<Hint value={value} style={this.hintStyle}>
<HintContent value={value} />
</Hint>
) : null}
</XYPlot>
</div>
);
}
}
export default ChartGridline;