Reputation: 67
I've been following Max Schwarzmueller's React course on Udemy, and everything has been going well so far until now. As I was following along with his lectures, I encountered a bug that I cannot for the life of me figure out.
The project in question is an expense tracker, and the bug itself has to do with a chart that measures how much a given month contributes to the year's expenses. A dataPoints prop is passed from ExpensesChart (the parent component) to Chart (the child component), and that is used to render each of the ChartBars (child component of Chart) in turn. The values of each of the points is then assigned to an array using map() so that the max can be found using Math.max(), but for some reason, trying to load the site throws an error:
TypeError: Cannot read property 'map' of undefined
5 | const dataPointValues = props.dataPoints.map(dataPoint => dataPoint.value);
Here's the code to all three:
ExpensesChart.js:
import Chart from "../Chart/Chart";
function ExpensesChart(props) {
const chartDataPoints = [
{ label: "Jan", value: 0 },
{ label: "Feb", value: 0 },
{ label: "Mar", value: 0 },
{ label: "Apr", value: 0 },
{ label: "May", value: 0 },
{ label: "Jun", value: 0 },
{ label: "Jul", value: 0 },
{ label: "Aug", value: 0 },
{ label: "Sep", value: 0 },
{ label: "Oct", value: 0 },
{ label: "Nov", value: 0 },
{ label: "Dec", value: 0 },
];
for (const expense of props.expenses) {
const expenseMonth = expense.date.getMonth(); // 0-indexed
chartDataPoints[expenseMonth].value += expense.amount;
}
return <Chart dataPoints={chartDataPoints} />;
}
export default ExpensesChart;
Chart.js:
import ChartBar from "./ChartBar";
import "./Chart.css";
function Chart(props) {
const dataPointValues = props.dataPoints.map(dataPoint => dataPoint.value);
const totalMaximum = Math.max(...dataPointValues);
return (
<div className="chart">
{props.dataPoints.map((dataPoint) => (
<ChartBar
key={dataPoint.label}
value={dataPoint.value}
maxValue={totalMaximum}
label={dataPoint.label}
/>
))}
</div>
);
}
export default Chart;
ChartBar.js:
import "./ChartBar.css";
function ChartBar(props) {
let barFillHeight = "0%";
if (props.maxValue > 0) {
barFillHeight = Math.round((props.value / props.maxValue) * 100) + "%";
}
return (
<div className="chart-bar">
<div className="chart-bar__inner">
<div
className="chart-bar__fill"
style={{ height: barFillHeight }}
></div>
</div>
<div className="chart-bar__label">{props.label}</div>
</div>
);
}
export default ChartBar;
I am almost certain that chartDataPoints (the value that is passed to Chart via its props) exists, so I don't know what's wrong. Some other answers on this site and others eluded to it having to do with components being loaded asynchronously, but I'm not sure if that applies here, since some of those posts used AJAX.
Any help would be appreciated!
Edit: I'm encountering more weird behavior. I figured I might try debugging via Chrome's DevTools, but upon inspection, ExpensesChart is nowhere to be found in the file tree under the Sources tab. Here's a picture:
Additionally, any console.log() statements placed anywhere in the ExpensesChart file (at the beginning or end of the function, and even outside it) do not register in the console. Is this happening because of the error?
I tried specifying the data type of dataPointValues explicitly, but that still does not work fully. The page actually loads when this is done, but the chart does not display correctly. The code now reads as such:
import ChartBar from "./ChartBar";
import "./Chart.css";
Chart.defaultProps = {
dataPoints: []
}
function Chart(props) {
const dataPointValues = props.dataPoints.map(dataPoint => dataPoint.value);
const totalMaximum = Math.max(...dataPointValues);
return (
<div className="chart">
{props.dataPoints.map((dataPoint) => (
<ChartBar
key={dataPoint.label}
value={dataPoint.value}
maxValue={totalMaximum}
label={dataPoint.label}
/>
))}
</div>
);
}
export default Chart;
And it looks like this:
...that is to say, blank.
Upvotes: 1
Views: 299
Reputation: 11
In my case I changed in the file ExpensesChart.js from dataPoint={chartDataPoints} to dataPoints={chartDataPoints} and It works.
Upvotes: 1
Reputation: 67
Oh my god. I figured it out.
In Expenses.js (a file I did not include that's the parent to ExpensesChart), I wrote the following line:
import ExpensesChart from "../Chart/Chart";
I changed it to:
import ExpensesChart from "../Expenses/ExpensesChart";
...and it worked perfectly. Sigh...
Upvotes: 1
Reputation: 2810
Check whether or not the your props.dataPoints
is undefined
.
Replace this line:
const dataPointValues = props.dataPoints.map(dataPoint => dataPoint.value);
with this:
const dataPointValues = props.dataPoints && props.dataPoints.map(dataPoint => dataPoint.value);
Upvotes: 1