Floky99
Floky99

Reputation: 712

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>

Upvotes: 5

Views: 69073

Answers (5)

Ali
Ali

Reputation: 21

Prevent accessing non existing element in your array
You try to access element of an empty array in your html code which causes this error since html is executed before you set data in useEffect

Which means you have no value in your array, ? operator in value?.arr[0] only works for the array but not for it's elements, just use value?.arr?.[0]

solution:

 <div>info: {value?.arr?.[0].name}</div>

2nd solution that would fit in your restaurant code:

{value?.arr?.length > 0 && <>
  <div>info: {value.arr[0].name}</div>
  <div>disabled: {value.arr[0].disabled? "disabled" : "enabled"}</div>
</>
}'

PS: Guess most of ppl just care about the error not the specific code that this post has

Upvotes: 0

Erik P_yan
Erik P_yan

Reputation: 788

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.

Upvotes: 1

BlueDragon
BlueDragon

Reputation: 55

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>
  );

Upvotes: 1

Dejan Janjušević
Dejan Janjušević

Reputation: 3230

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.

Upvotes: 0

Mark Williams
Mark Williams

Reputation: 381

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]);

Upvotes: 0

Related Questions