My Images.js
is as follows:
import { useState, useEffect } from "react";
import axios from "axios";
import styled from "styled-components";
import ImageSlider_1 from "./ImageSlider_1";
const url = "https://hp-api.onrender.com/api/characters";
function Images() {
const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState(false);
const [characters, setCharacters] = useState([]);
useEffect(() => {
const fetchCharacters = async () => {
try {
const response = await axios(url);
const data = await response.data;
data.map((character) => {
if (character.image.localeCompare("")) {
setCharacters((characters) => [...characters, character]);
}
});
} catch (error) {
setIsError(true);
console.log(error);
}
setIsLoading(false);
};
fetchCharacters(); }, []);
return (
<Wrapper>
<ImageSlider_1 characters={characters} />
{/* <Carousel_Swiper characters={characters} /> */}
</Wrapper> ); }
const Wrapper = styled.section``;
export default Images;
My ImageSldier_1.js
is as follows:
import { useState } from "react";
import styled from "styled-components";
function ImageSlider_1({ characters }) {
console.log(characters[0].image);
// const [sliderData, setSliderData] = useState(characters[0].image);
return (
<Wrapper>
{characters.map((character) => {
return (
<img src={character.image} alt={character.name} key={character.id} />
);
})}
</Wrapper>
);
}
const Wrapper = styled.section``;
export default ImageSlider_1;
I am not sure why characters[0].image
gives me error as this:
Uncaught TypeError: Cannot read properties of undefined (reading
‘image’)
However, when I do console.log(characters);
instead, it shows me there are 25 items.
I can do characters.map((character) => console.log(character.image));
to display each of the image link, but then I need to set first image in the state variable:
const [sliderData, setSliderData] = useState(characters[0].image);
I am not sure what I am doing wrong.
2
Answers
You can use the
Array#map
function since `characters is an array.If
characters
is an empty array ([]
), the first element of it ([0]
) will be equal toundefined
. And if it’sundefined
, trying to accessimage
property (.image
) will result in an error, sinceundefined
does not have such property.You could use optional chaining (
?
) to secure ifcharacters[0]
isundefined
:To set the
state
value, you should adduseEffect
to listen tocharacters
changes and if it’s populated, set theimage
.characters
is initially an empty array in the parentImages
component:So on the initial render cycle the value
[]
is passed toImageSlider_1
as a prop value until theuseEffect
hook inImages
runs and fetches and updates thecharacters
state and rerenders itself and its sub-ReactTree. There’s no zero’th element to access animage
property of and the error is thrown.Now while you could store the passed
characters[0].image
into local state, using auseEffect
hook to synchronize it, this is actually considered a React anti-pattern. Don’t store the passed prop values in local state, and don’t store derived state in local state. Just reference the passed prop value directly and compute the derived state.Just about 100% of the time if you catch that you’ve coded a
useState
/useEffect
combo you should really use theuseMemo
hook.Instead of
use