Вопрос или проблема
Я пытаюсь получить данные из бэкенда и отобразить их на фронтенде моего приложения. Я использую fetch API, и CORS настроен правильно на бэкенде.
Когда компонент загружает данные, они не отображаются на фронтенде, поэтому я добавил console.log как способ отладки и понимаю, что мой
'const data = await response.json()'
console.log(data)
обещание выполняется и отображается в консоли. Когда я также вывожу в консоль console.log( setData( data.dataProducts ));
, я вижу undefined в консоли.
Я установил тернарный оператор в функции map, чтобы предотвратить сбой моего приложения, но перед этим в консоли появляется ошибка: невозможно прочитать свойства undefined (чтение ‘map’).
Мой бэкенд работает нормально, я протестировал его на Thunder Client, и он отображается. Я также протестировал в браузере, вставив этот маршрут: ‘http://localhost:8080/data’, и он тоже отображает мои данные в формате JSON на бэкенде.
Мои вопросы: Почему состояние set является undefined и почему свойства map являются undefined? Мне действительно нужна ваша помощь. Пожалуйста, простите меня за форматирование кода. Спасибо. Мои компоненты:
const Shopstore = () => {
const [dataProducts, setData] = useState([]);
const url = "http://localhost:8080/data";
useEffect(() => {
const fetchfunc = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("проблемы с сетью, пожалуйста, подождите ");
}
const data = await response.json();
console.log(data);
console.log(setData(data.dataProducts));
} catch (error) {
console.log("ошибка", error);
}
};
fetchfunc();
}, []);
return (
<div className="Shopstore mt-5">
<Container>
<Row>
<Col md={10} className="big mt-3">
{dataProducts ? (
dataProducts.map((product) => {
return <Listings key={product._id} {...product} />;
})
) : (
<p>нет данных</p>
)}
</Col>
</Row>
</Container>
</div>
);
};
export default Shopstore;
//компонент-дочерний
const Listings = (products) => {
const { image, heading, price, _id } = products;
return (
<div className="listings mt-3 mb-3">
<Container>
<Row>
<Col md={4} id={_id}>
<div className="card mx-auto" style={{ width: "250px" }}>
<Card>
<div className="image mx-auto ">
<Link to={`/shop/${products._id}`}>
<img
src={image}
alt=""
className="img-fluid"
style={{ width: "300px" }}
/>
</Link>
<CardBody>
<div className="title">
<h5>{heading}</h5>
</div>
<div className="price">
<span>{price}</span>
</div>
<div className=" mx-auto">
<button className="mx-auto cartbutton">
Добавить в корзину
</button>
</div>
</CardBody>
</div>
</Card>
</div>
</Col>
</Row>
</Container>
</div>
);
};
export default Listings
Ответ или решение
Ошибка "cannot read properties of undefined (reading ‘map’)" вызвана тем, что вы пытаетесь вызвать метод map
на переменной, которая равна undefined
. Давайте разберем ваш код, чтобы понять, почему это происходит и как это исправить.
Анализ проблемы
Вы описали, что данные успешно загружаются из вашего API и отображаются в консоли, но при попытке установить эти данные в состояние с помощью setData(data.dataProducts)
вы видите undefined
. Это связано с тем, что setData
не возвращает значение, поэтому результат console.log(setData(data.dataProducts));
всегда будет undefined
. Функция setData
просто обновляет состояние и не возвращает никаких данных.
Таким образом, нам нужно:
- Убедиться, что
data.dataProducts
действительно существует и имеет правильную структуру, прежде чем мы попытаемся установить его в состояние. - Правильно обрабатывать ситуацию, когда данных нет (например, в случае ошибки или если данные не были загружены).
Возможное исправление
Следует инициировать состояние dataProducts
как null
или undefined
, а затем проверить его перед вызовом map
, чтобы избежать ошибки.
Вот пример того, как можно изменить ваш код:
const Shopstore = () => {
const [dataProducts, setData] = useState(null); // изначально устанавливаем null
const url = "http://localhost:8080/data";
useEffect(() => {
const fetchfunc = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("network issues pls wait ");
}
const data = await response.json();
console.log(data);
setData(data.dataProducts || []); // если dataProducts нет, установить пустой массив
} catch (error) {
console.log("error", error);
}
};
fetchfunc();
}, []);
return (
<div className="Shopstore mt-5">
<Container>
<Row>
<Col md={10} className="big mt-3">
{dataProducts && dataProducts.length > 0 ? ( // проверяем на наличие данных
dataProducts.map((product) => {
return <Listings key={product._id} {...product} />;
})
) : (
<p>no data</p>
)}
</Col>
</Row>
</Container>
</div>
);
};
export default Shopstore;
Объяснение изменений
- Инициализация состояния: Вместо массива
[]
, состояниеdataProducts
теперь инициализировано какnull
. Это позволяет легче проверять его наличие. - Проверка данных: В JSX-коде мы добавили проверку на
dataProducts && dataProducts.length > 0
, чтобы убедиться, что данные загружены и это массив, прежде чем мы будем его маппить. - Установка состояния: Установили
setData(data.dataProducts || [])
, что означает, что еслиdataProducts
нет, мы установим пустой массив, избегая дальнейших ошибок.
Таким образом, вы устраните ошибку "cannot read properties of undefined (reading ‘map’)" и гарантируете, что ваше приложение будет обрабатывать состояние корректно.
После применения этих изменений у вас должно работать корректное отображение данных и не возникнуть ошибок, связанных с отсутствующими свойствами.