'Cannot read properties of undefined (reading '0')

I have a page coded in React with NextJS hooks, when I try to render a page the error says what's in the title, I presume because the object which I'm mapping is empty/undefined on first load. I added "?" to every map I have on the page and it's still giving me this error... I noticed that if I stay on that page after it gives me error and press "Ctrl + shift + r" the page loads normally. What could be causing this?

import {Fragment, useEffect} from "react";
import Head from "next/head";
import DashboardPage from "../../../../components/components/dashboard/DashboardPage";
import LayoutDashboard from "../../../../components/layout/LayoutDashboard";
import React from "react";
import Pusher from "pusher-js";
import useSWR, {mutate} from "swr";

const fetcher = async () => {
  const response1 = await fetch("API");
  const data1 = await response1.json();


  const props = {
    data: data1,
  };
  return props;
};

export default function Dashboard(props) {
  const {data, error} = useSWR("data", fetcher);

  useEffect(() => {
    //Pusher.logToConsole = true;
    var pusher = new Pusher("pshr", {
      cluster: "eu",
    });
    const channel = pusher.subscribe("chnl");
    channel.bind("chnl", function (data) {
      console.log(data);
      mutate("data");
    });
  }, []);

  if (error) return "Error";
  if (!data) return "Loading";

  console.log(data);
  return (
    <Fragment>
      <Head>
        <title>Dashboard</title>
        <link rel="icon" href="/favicon.ico" />
       
      </Head>

      <LayoutDashboard restaurantData={props?.restaurantData[0]}>
        <DashboardPage
          orders={data?.showItemsOnOrder}
          dashboardCards={data?.dashboardCardInfo}
          ordersGraph={data?.dashboardGraph}
        />
      </LayoutDashboard>
    </Fragment>
  );
}

export async function getStaticPaths() {
  const response = await fetch(`API`);
  const data = await response.json();

  const tables = [];
  for (var i = 1; i <= data[0].restaurantTables; i++) {
    tables.push({
      restaurant: data[0].queryName,
      tableNr: i.toString(),
    });
  }

  return {
    paths: tables.map((table) => {
      return {
        params: {
          restaurantName: table.restaurant,
          tableNr: table.tableNr,
        },
      };
    }),
    fallback: false,
  };
}

export async function getStaticProps() {
  const response = await fetch(`API`);
  const data = await response.json();

  return {
    props: {
      restaurantData: data,
    },
    revalidate: 1,
  };
}

EDIT I recognized that the site works normally if I go straight to the link that I want... It stops working when I'm calling components with Link tags in nextJS then it throws an error that it's in title... So if I go straight to the link everything works as expected maybe that is also the reason that the page works if I click on my link and then refresh it... So what could be the problem with Link tag? This is my code for it:

<Link
       href={{
              pathname: "/restaurant/restaurantName/dashboard/",
              query: {restaurantName: restaurantName},
            }}
          >
            <div
              className={
                router.pathname == "/restaurant/[restaurantName]/dashboard"
                  ? "text-blue-600 bg-gray-50"
                  : "text-gray-700 "
              }
            >
              <div className="flex p-3  space-x-4 0 hover:bg-gray-50 hover:text-blue-600  cursor-pointer">
                <DonutLargeIcon className=" text-gray-300" />
                <p className="">Dashbord</p>
              </div>
            </div>
          </Link>


Solution 1:[1]

1-if data is undefined on the first component render I think this approach will work

  • first-time data is undefined
  • sec time data is fetched then u can use as below
const fetcher = async () => {
  const response1 = await fetch("API");
  const data1 = await response1.json();


  const props = {
    data: data1,
  };
  return props;
};
  • if look at ur fetching function u return props= {data: data1}
  • const {data} =useSWR("data",fetching) it should be data.data.showItemOnOrder
return (
    <Fragment>
      <Head>
        <title>Dashboard</title>
        <link rel="icon" href="/favicon.ico" />
       
      </Head>

      <LayoutDashboard restaurantData={props?.restaurantData[0]}>
       {data&& <DashboardPage
          orders={data.data.showItemsOnOrder}
          dashboardCards={data.data.dashboardCardInfo}
          ordersGraph={data.data.dashboardGraph}
        />}
      </LayoutDashboard>
    </Fragment>
  );

Solution 2:[2]

Your useEffect needs data in it's dependency array for it to trigger a rerender based on data. Also, you'll need if (!data) return at the top of this useEffect to prevent the error.

So:

useEffect(() => {
    //Pusher.logToConsole = true;
    if (!data) return

    var pusher = new Pusher("pshr", {
      cluster: "eu",
    });

    const channel = pusher.subscribe("chnl");

    channel.bind("chnl", function (data) {
      console.log(data);
      mutate("data");
    });
  }, [data]);

Solution 3:[3]

What could be causing this?

The data is undefined in your function getStaticPaths.

  export async function getStaticPaths() {
    const response = await fetch(`API`);
    const data = await response.json(); // <-- here, your data is undefined

Now I don't use fetch, but I think it doesn't throw in case of 4xx or 4xx errors. Checking MDN yes, you need to check if the response is actually OK. Something like this:

  export async function getStaticPaths() {
    const response = await fetch(`API`);
    if (!response.ok) {
      throw new Error('Network response was not OK');
    }

    const data = await response.json(); // <-- now this won't be undefined

You can read more about this behavior here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#checking_that_the_fetch_was_successful

EDIT Sorry, I have just noticed that you also reference props?.restaurantData[0].

So instead of <LayoutDashboard restaurantData={props?.restaurantData[0]}> use <LayoutDashboard restaurantData={props?.restaurantData ? props?.restaurantData[0] : undefined}> like here:

<LayoutDashboard restaurantData={props?.restaurantData ? props.restaurantData[0] : undefined}>
  <DashboardPage
    orders={data?.showItemsOnOrder}
    dashboardCards={data?.dashboardCardInfo}
    ordersGraph={data?.dashboardGraph}
  />
</LayoutDashboard>

That's because, by putting an optional chaining operator (?) after props, you only try to read restaurantData if props is not undefined. But since it's not, then you try to access the first element in restaurantData by using restaurantData[0] without checking if restaurantData is actually defined.

Check that the restaurantData is defined and access restaurantData[0] only if it's defined.

Solution 4:[4]

For someone who has tried get data from array inside an object and got this error - you can try to check with length like this way:

object?.array.length ? object?.array?.someItem![0] : 'not exist'

Take attention that we check with chaining sign ([?]) and logical NOT (!) for more safe search.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BlueDragon
Solution 2 Mark Williams
Solution 3
Solution 4