Reactjs Routing и useParams Hook

Я получаю данные из 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 />} />

Кажется, что маршрут отображает страницу с подробностями, а не страницу, которая не найдена, но, возможно, ваши разрозненные фрагменты затрудняют понимание вашего кода. Можете ли вы поделиться Минимальный, Полный и воспроизводимый пример кода? Не могли бы вы также прояснить, в чем проблема, включая этапы воспроизведения?

Drew Reese 30.03.2021 07:16

@DrewReese, эй, я прикрепил ссылку codeanbox, вот почему переменная продукта возвращается как null, когда я ввожу доступный идентификатор, например / 2, в URL-адрес корневой страницы. ошибка говорит: «не удается прочитать имя свойства с нулевым значением» ссылка на сайт

Nawaz Mohamed 30.03.2021 11:28
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
47
1

Ответы 1

Вы переименовали возвращенный объект 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>
);

Edit reactjs-routing-and-useparams-hook

Примечание: если вы хотите сделать это в ловушке 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": "." }, а не массив продуктов, извините, я не могу найти способ отформатировать блок кода
Nawaz Mohamed 01.04.2021 05:07

@NawazMohamed Ничего страшного, комментарии на самом деле не предназначены для фрагментов кода. Если fetch действительно возвращает только один объект-элемент, я бы назвал его product, и тогда проверка «страница не найдена» будет if (!product) return <PageNotFound />, и вы можете отбросить фильтр, так как у вас уже есть объект product, который вы хотите визуализировать.

Drew Reese 01.04.2021 05:44

Другие вопросы по теме