Reputation: 27
I am learning reactjs and I'm trying to plot bar graph. So I'm trying to plot population race graph which change over the time and looks like this. Population race bar chart
For plotting graph I am using chart-race-react. But it seems like I'm doing something wrong in my code.
My code:
import React, { Component } from 'react';
import BarChart from 'chart-race-react';
import './App.css';
const API_URL = 'https://example.json';
const randomColor = () => {
return `rgb(${255 * Math.random()}, ${255 * Math.random()}, ${255})`;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
countries: []
}
}
componentDidMount() {
fetch(API_URL)
.then(v => v.json())
.then(array => {
const dataForVisualisation = {};
array.forEach(element => {
const countryName = element['Country Name'];
if (!dataForVisualisation[countryName]) {
dataForVisualisation[countryName] = [];
}
dataForVisualisation[countryName].push(element.Value);
});
this.setState({countries: dataForVisualisation});
})
}
render() {
return (
<div style={{width: "500px"}}>
<BarChart
start={true}
data = {this.state.countries}
len = {this.state.countries[Object.keys(this.state.countries)[0]].length}
keys = {Object.keys(this.state.countries)}
timeout={400}
delay={100}
colors = {Object.keys(this.state.countries).reduce((res, item) => ({
...res,
...{ [item]: randomColor() }
}), {})}
labels = {Object.keys(this.state.countries).reduce((res, item, idx) => {
return{
...res,
...{[item]: (
<div style={{textAlign:"center",}}>
<div>{item}</div>
</div>
)}
}}, {})}
timeline = {Array(20).fill(0).map((itm, idx) => idx + 1)}
timelineStyle={{
textAlign: "center",
fontSize: "50px",
color: "rgb(148, 148, 148)",
marginBottom: "100px"
}}
textBoxStyle={{
textAlign: "right",
color: "rgb(133, 131, 131)",
fontSize: "30px",
}}
barStyle={{
height: "60px",
marginTop: "10px",
borderRadius: "10px",
}}
width={[15, 75, 10]}
maxItems = {this.state.countries.length}
/>
</div>
);
}
}
export default App;
I'm encountering TypeError: this.state.countries[Object.keys(...)[0]] is undefined
error because my data is undefined here. How should I change my code to make my output as shown in gif
? Is there any other library for doing this ?
Upvotes: 2
Views: 415
Reputation: 5862
I found an issue on your code like in len
property of the BarChart
that gets the error Cannot read property 'length' of undefined. After I used null checking with question mark, I am not getting any error but printing 1 to 20. I am not sure it helps you or not. May be after changing that, you will get it solved.
len={this.state.countries[Object.keys(this.state.countries)[0]].length}
replaced by
len={this.state.countries[Object.keys(this.state.countries)[0]]?.length}
Upvotes: 1
Reputation: 3724
You should just wait until countries is filled before trying to render anything. You can for example render BarChart component only if countries array has at least one element :
[...]
{this.state.countries.length > 0 && <BarChart
start={true}
data = {this.state.countries}
len = {this.state.countries[Object.keys(this.state.countries)[0]].length}
keys = {Object.keys(this.state.countries)}
timeout={400}
delay={100}
colors = {Object.keys(this.state.countries).reduce((res, item) => ({
...res,
...{ [item]: randomColor() }
}), {})}
labels = {Object.keys(this.state.countries).reduce((res, item, idx) => {
return{
...res,
...{[item]: (
<div style={{textAlign:"center",}}>
<div>{item}</div>
</div>
)}
}}, {})}
timeline = {Array(20).fill(0).map((itm, idx) => idx + 1)}
timelineStyle={{
textAlign: "center",
fontSize: "50px",
color: "rgb(148, 148, 148)",
marginBottom: "100px"
}}
textBoxStyle={{
textAlign: "right",
color: "rgb(133, 131, 131)",
fontSize: "30px",
}}
barStyle={{
height: "60px",
marginTop: "10px",
borderRadius: "10px",
}}
width={[15, 75, 10]}
maxItems = {this.state.countries.length}
/>}
{this.state.countries.length === 0 && <span>Loading...</span>}
[...]
Note the conditional rendering syntax.
Upvotes: 0