Я получаю данные из API и сохраняю массив в переменной «products» и обращаюсь к параметрам-заполнителям в URL-адресе запроса при попытке перейти на мою страницу с помощью маршрута, но когда я пытаюсь перейти на страницу типа http: // localhost: 3000 / shoes / 4 'должен вернуть страницу с текстом «Страница не найдена», а не страницу сведений. Поясните, пожалуйста, почему этого не происходит. Сервер Json находится в порту 3001
UseFetch.js
import { useState, useEffect } from "react";
const baseUrl = "http://localhost:3001/";
export default function useFetch(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`${baseUrl}${url}`)
.then((response) => {
return response.json();
})
.then((data) => {
setData(data);
})
.catch((error) => {
setError(error);
})
.finally(() => {
setLoading(false);
});
}, [url]);
return { data, error, loading };
}
набор продуктов
{
"id": 1,
"category": "shoes",
"image": "shoe1.jpg",
"name": "Hiker",
"price": 94.95,
"skus": [
{ "sku": "17", "size": 7 },
{ "sku": "18", "size": 8 }
],
"description": "This rugged boot will get you up the mountain safely."
},
{
"id": 2,
"category": "shoes",
"image": "shoe2.jpg",
"name": "Climber",
"price": 78.99,
"skus": [
{ "sku": "28", "size": 8 },
{ "sku": "29", "size": 9 }
],
"description": "Sure-footed traction in slippery conditions."
},
{
"id": 3,
"category": "shoes",
"image": "shoe3.jpg",
"name": "Explorer",
"price": 145.95,
"skus": [
{ "sku": "37", "size": 7 },
{ "sku": "38", "size": 8 },
{ "sku": "39", "size": 9 }
],
"description": "Look stylish while stomping in the mud."
},
{
"id": 4,
"category": "headphone",
"image": "headphone3.jpg",
"name": "headphone red",
"price": 100,
"description": "Red colored headphone"
},
{
"id": 5,
"category": "headphone",
"image": "headphone2.jpg",
"name": "headphone blue",
"price": 90,
"description": "Blue colored headphone"
},
{
"id": 6,
"category": "headphone",
"image": "headphone1.jpg",
"name": "headphone black",
"price": 80,
"description": "Black colored headphone"
}
Получение данных в массив товаров
const { category, id } = useParams();
const { data: products, error, loading } = useFetch(
`products?category=${category}&id=${id}`
);
Направление на страницу, которая не найдена, если массив товаров пуст
if (products.length === 0) {
return <PageNotFound />;
}
Направление на страницу сведений с маршрутизацией
<Route path = "/:category/:id" element = {<Detail />} />
@DrewReese, эй, я прикрепил ссылку codeanbox, вот почему переменная продукта возвращается как null, когда я ввожу доступный идентификатор, например / 2, в URL-адрес корневой страницы. ошибка говорит: «не удается прочитать имя свойства с нулевым значением» ссылка на сайт



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы переименовали возвращенный объект data в products, и я уверен, что вы намеревались деструктурировать вложенный массив products из data.
const {
data: { products }, // <-- destructure products instead of rename data
error,
loading
} = useFetch(`products/${id}`);
Теперь проверка products.length будет фактически проверять объект массива.
if (!products.length) {
return <PageNotFound />;
}
Остается проблема с отображением определенного «продукта» или набора совпадающих «продуктов». Здесь ваш код выглядит немного странно, поскольку вы передаете и категорию, и идентификатор конечной точке API, а fetch не выполняет никакой обработки / фильтрации ответов, а возвращает весь ответ JSON. Я предполагаю, что пользовательский интерфейс будет обрабатывать массив products для сопоставления продуктов по category и id.
if (!products.length) return <PageNotFound />;
const product = products.find(
(product) => product.category === category && `${product.id}` === id
);
return (
<div id = "detail">
<h1>{product.name}</h1>
<p>{product.description}</p>
<p id = "price">${product.price}</p>
<img src = {`/images/${product.image}`} alt = {product.category} />
</div>
);
Примечание: если вы хотите сделать это в ловушке useFetch и по-прежнему возвращать массив, используйте Array.prototype.filter, используя те же условия, и помните, что любой отображаемый контент по-прежнему будет в массиве, поэтому вам нужно будет сопоставить результат или сдвинуть / вывести результат с передней / задней части массива products.
Дополнительная проблема заключается в том, что ваша ловушка useFetch не «сбрасывает» состояние loading, когда url обновляется и эффект запускается снова. Исправление здесь состоит в том, чтобы дать изначально ложное состояние loading и установить его истинным, когда начинается выборка.
export default function useFetch(url) {
const [data, setData] = useState(products);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false); // <-- default false
useEffect(() => {
setLoading(true); // <-- toggle true when starting fetch
fetch(`${baseUrl}${url}`)
.then((response) => {
return response.json();
})
.then((data) => {
setData(data);
})
.catch((error) => {
setError(error);
})
.finally(() => {
setLoading(false);
});
}, [url]);
return { data, error, loading };
}
const { data: { products }, // <-- destructure products instead of rename data error, loading } = useFetch(products / $ {id} ); Здесь URL выборки 'localhost: 3001 / products / 2' должен возвращать один продукт, такой как этот { "id": 2, "category": "shoes", "image": "shoe2.jpg", "name": "Climber", "price": 78.99, "skus": [ { "sku": "28", "size": 8 }, { "sku": "29", "size": 9 } ], "description": "." }, а не массив продуктов, извините, я не могу найти способ отформатировать блок кода
@NawazMohamed Ничего страшного, комментарии на самом деле не предназначены для фрагментов кода. Если fetch действительно возвращает только один объект-элемент, я бы назвал его product, и тогда проверка «страница не найдена» будет if (!product) return <PageNotFound />, и вы можете отбросить фильтр, так как у вас уже есть объект product, который вы хотите визуализировать.
Кажется, что маршрут отображает страницу с подробностями, а не страницу, которая не найдена, но, возможно, ваши разрозненные фрагменты затрудняют понимание вашего кода. Можете ли вы поделиться Минимальный, Полный и воспроизводимый пример кода? Не могли бы вы также прояснить, в чем проблема, включая этапы воспроизведения?