I have a component Dashboard.js that will render upon NavLink click, but upon refresh the page crashes. I am stumped about what to do.
The error says cannot read properties of undefinded (Budget)
Upon NavLink click, the page will not render the chart using "goalsChartData." When I refresh, the whole thing crashes. If I navigate to '/home' then click back on Dashboard.js, the budget data does populate the chart/the page loads, but still from here if I refresh, it crashes.
import React from "react";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
LineChart,
Line,
} from "recharts";
const Dashboard = ({ user, budget, personBudget }) => {
// data for Goals Chart
// data for Goals Chart
// data for Goals Chart
const goalsChartData = [
{
name: "Week 1",
Goal: user.budget ? user.budget.weekOneGoals : null,
},
{
name: "Week 2",
Goal: user.budget ? user.budget.weekTwoGoals : null,
},
{
name: "Week 3",
Goal: user.budget ? user.budget.weekThreeGoals : null,
},
{
name: "Week 4",
Goal: user.budget ? user.budget.weekFourGoals : null,
},
{
name: "Week 5",
Goal: user.budget ? user.budget.weekFiveGoals : null,
},
{
name: "Week 6",
Goal: user.budget ? user.budget.weekSixGoals : null,
},
];
// data for Friends Chart
// data for Friends Chart
// data for Friends Chart
const friendsChartData = [
{
name: "Week 1",
Person1: personBudget[0] ? personBudget[0].weekOneGoals : null,
Person2: personBudget[1] ? personBudget[1].weekOneGoals : null,
Person3: personBudget[2] ? personBudget[2].weekOneGoals : null,
},
{
name: "Week 2",
Person1: personBudget[0] ? personBudget[0].weekTwoGoals : null,
Person2: personBudget[1] ? personBudget[1].weekTwoGoals : null,
Person3: personBudget[2] ? personBudget[2].weekTwoGoals : null,
},
{
name: "Week 3",
Person1: personBudget[0] ? personBudget[0].weekThreeGoals : null,
Person2: personBudget[1] ? personBudget[1].weekThreeGoals : null,
Person3: personBudget[2] ? personBudget[2].weekThreeGoals : null,
},
{
name: "Week 4",
Person1: personBudget[0] ? personBudget[0].weekFourGoals : null,
Person2: personBudget[1] ? personBudget[1].weekFourGoals : null,
Person3: personBudget[2] ? personBudget[2].weekFourGoals : null,
},
{
name: "Week 5",
Person1: personBudget[0] ? personBudget[0].weekFiveGoals : null,
Person2: personBudget[1] ? personBudget[1].weekFiveGoals : null,
Person3: personBudget[2] ? personBudget[2].weekFiveGoals : null,
},
{
name: "Week 6",
Person1: personBudget[0] ? personBudget[0].weekSixGoals : null,
Person2: personBudget[1] ? personBudget[1].weekSixGoals : null,
Person3: personBudget[2] ? personBudget[2].weekSixGoals : null,
},
];
return (
<div
style={{
background: "grey",
display: "grid",
justifyContent: "center",
}}
>
<h4 style={{ textAlign: "center" }}>Your Goals</h4>
<BarChart
width={500}
height={300}
data={goalsChartData}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
barSize={30}
>
<XAxis dataKey="name" scale="point" padding={{ left: 10, right: 10 }} />
<YAxis />
<Tooltip />
<Legend />
<CartesianGrid strokeDasharray="3 3" />
<Bar dataKey="Goal" fill="#8884d8" />
</BarChart>
<LineChart
width={500}
height={300}
data={friendsChartData}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line
type="monotone"
dataKey="Person2"
stroke="#8884d8"
strokeDasharray="5 5"
/>
<Line
type="monotone"
dataKey="Person1"
stroke="#82ca9d"
strokeDasharray="3 4 5 2"
/>{" "}
<Line
type="monotone"
dataKey="Person3"
stroke="#e21c7f"
strokeDasharray="3 4 5 2"
/>
</LineChart>
</div>
);
};
export default Dashboard;
App.js
import "./App.css";
import { Routes, Route } from "react-router-dom";
import { useEffect, useState } from "react";
import Login from "./pages/Login";
import Signup from "./pages/Signup";
import { Paper } from "@material-ui/core";
import Navbar from "./components/Navbar";
import Home from "./components/Home";
import Profile from "./components/Profile";
import RequireAuth from "./pages/RequireAuth";
import useStyles from "./pages/useStyles";
import Budget from "./components/Goals";
import ProfileDelete from "./pages/ProfileDelete";
import People from "./components/People";
import Friends from "./components/Friends";
import Person from "./components/Person";
import Dashboard from "./components/Dashboard";
import Goals from "./components/Goals";
function App() {
const [user, setUser] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const classes = useStyles();
const [people, setPeople] = useState([]);
const [userFriends, setUserFriends] = useState([]);
const [budget, setBudget] = useState([]);
const [personBudget, setPersonBudget] = useState([]);
useEffect(() => {
fetch("/authorize_user").then((res) => {
if (res.ok) {
res.json().then((user) => {
setIsAuthenticated(true);
setUser(user);
});
}
});
fetch("/people").then((res) => {
if (res.ok) {
res.json().then(setPeople);
}
});
fetch("/friends").then((res) => {
if (res.ok) {
res.json().then(setUserFriends);
}
});
fetch("/budgets").then((res) => {
if (res.ok) {
res.json().then(setBudget);
}
});
fetch("/person_budgets").then((res) => {
if (res.ok) {
res.json().then(setPersonBudget);
}
});
}, []);
// useEffect(() => {
// }, [])
return (
<>
<Paper className={classes.pageContent} elevation={24}>
<Navbar
user={user}
setUser={setUser}
isAuthenticated={isAuthenticated}
setIsAuthenticated={setIsAuthenticated}
/>
</Paper>
<Routes>
<Route
path="login"
element={
<Login
user={user}
setUser={setUser}
isAuthenticated={isAuthenticated}
setIsAuthenticated={setIsAuthenticated}
/>
}
/>
<Route
path="signup"
element={
<Signup
user={user}
setUser={setUser}
isAuthenticated={isAuthenticated}
setIsAuthenticated={setIsAuthenticated}
/>
}
/>
<Route path="/" element={<Home />} />
<Route
path="home"
element={
<Paper className={classes.pageContent}>
<Home />{" "}
</Paper>
}
/>
<Route
path="profile"
element={
// <RequireAuth isAuthenticated={isAuthenticated}>
<Paper className={classes.pageContent}>
<Profile
user={user}
setUser={setUser}
isAuthenticated={isAuthenticated}
setIsAuthenticated={setIsAuthenticated}
/>
</Paper>
//{" "}
// </RequireAuth>s
}
/>
<Route
path="goals"
element={
<Paper className={classes.pageContent}>
<Goals user={user} budget={budget} />
</Paper>
}
/>
<Route
path="profile/delete"
element={
<ProfileDelete
user={user}
setUser={setUser}
setIsAuthenticated={setIsAuthenticated}
/>
}
/>
<Route
path="people"
element={
<People
people={people}
user={user}
setUser={setUser}
setIsAuthenticated={setIsAuthenticated}
userFriends={userFriends}
/>
}
/>
<Route
path="/friends"
element={
<Friends user={user} userFriends={userFriends} people={people} />
}
/>
<Route
path="/people/:id"
element={
<Paper className={classes.pageContent}>
<Person
user={user}
people={people}
userFriends={userFriends}
setUserFriends={setUserFriends}
/>
</Paper>
}
/>
<Route
path="dashboard"
element={
<Dashboard
user={user}
budget={budget}
personBudget={personBudget}
/>
}
/>
{/* <Route path="goals" element={<Goals user={user} />} /> */}
</Routes>
</>
);
}
export default App;
CodePudding user response:
The issue is because your API requests haven't finished loading yet which is why you are getting the undefined. For this scenario you need to include a loading state so something like this would work.
App.js
function App() {
... all of your code above render
const loaded = people && userFriends && budget && personBudget;
if (!loaded){
return '...loading'
}
return (
...what you already have in your render
)
}
Though I would encourage you to refactor your code as this many api calls and setStates in one file will cause a lot of re-renders. I would encourage you to look at the useContext
hook and create a provider for each of those api calls rather than have them all in the app.