Sometimes the app fails to connect to the database and retrieve the data I want. When this happens I get an error back saying "cannot read properties of undefined (reading 'map')."
I have tried to use a '?' so it only maps when the length of the array is greater than 0, i.e not empty. However I don't think this is working currently...
I want to handle this error without the page crashing. Any advice would be appreicated.
import axios from "axios";
import { Router, useRouter } from "next/router";
import { useEffect, useState } from "react";
function Class() {
const router = useRouter();
const classId = router.query.classId;
const yearId = router.query.yearId;
const weekId = router.query.weekId;
const [className, setClassname] = useState("");
const [cards, setCards] = useState<React.ReactElement[]>();
const [cardsForMatchingGame, setCardsForMatchingGame] = useState<React.ReactElement[]>();
const [flashcards, setFlashcards] = useState<React.ReactElement[]>();
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
useEffect(() => {
if (!router.isReady) return;
if (router.isReady && className) {
const fetchAllFlashcards = async () => {
setIsError(false);
setIsLoading(true);
try {
const res = await axios.get(`/api/ClassSelector/${yearId}/${weekId}/${className}`);
setFlashcards(res.data);
} catch (err) {
setIsError(true);
}
setIsLoading(false);
};
fetchAllFlashcards();
}
}, [router.isReady, className, weekId, yearId, classId]);
useEffect(() => {
if (!router.isReady || flashcards?.length === 0) return;
if (router.isReady && flashcards?.length !== 0) {
const deck = flashcards.map((card) => {
const { id, english, japanese, example_sentence, week, year } = card;
return (
<div key={id week year english} className="flex items-center justify-center">
<Flashcards
english={english}
japanese={japanese}
classPath={`https://eb-flashcards.vercel.app/ClassSelector/${yearId}/${weekId}/${className}`}
showDeleteButton={false}
/>
</div>
);
});
setCards(deck);
}
}, [router.isReady, flashcards, className, yearId, weekId])
return(<div>{cards}</div>)
}
CodePudding user response:
Sometimes flashcards
is null
or undefined
.
In javascript:
null?.length !== 0
and undefined?.length !== 0
are true.
So this condition:
if (router.isReady && flashcards?.length !== 0)
will be satisfied and js tries to call map
method of flashcards
which is null
or undefined
. Thus, the error occurs.
One way is to change the condition like so:
if (router.isReady && flashcards && flashcards?.length !== 0)
CodePudding user response:
As mentioned before: if your res.data is null or undefined it will pass the condition. But instead of checking for it, I would recommend to set falshcards to []
if res.data is falsy
(so something like this in your first useEffect:
try {
const res = await axios.get(`/api/ClassSelector/${yearId}/${weekId}/${className}`);
setFlashcards(res.data || []);
}...
Also you don't need your second useEffect or a state for cards. Is there any particular reason you want them? Your code would look way better if you got rid of those and instead doing something like:
function Class() {
....
useEffect(() => {
...
}
}, [router.isReady, className, weekId, yearId, classId]);
....
if (!falshcards || flashcards?.length === 0) return null;
// Instead of second useEffect and the return(<div>{cards}</div>):
return (
<>
{flashcards.map((card) => {
const {id, english, japanese, example_sentence, week, year} = card;
return (
<div key={id week year english} className="flex items-center justify-center">
<Flashcards
english={english}
japanese={japanese}
classPath={`https://eb-flashcards.vercel.app/ClassSelector/${yearId}/${weekId}/${className}`}
showDeleteButton={false}
/>
</div>
);
})}
</>
);
}
CodePudding user response:
You can check before iteration on flashcards.
const result = Array.isArray(arr) ? arr.map(element => element 1) : [];