'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 |