Home > Back-end >  React renders component upon NavLink click but crashed upon refresh
React renders component upon NavLink click but crashed upon refresh

Time:03-09

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.

  • Related