Что такое Fetch API в Javascript

Fetch API позволяет нам отправлять запросы на сервер и получать ответы. Он также предоставляет глобальный метод fetch(), упрощающий асинхронное получение ресурсов по сети.

Ниже приведен простой пример компонента реакции, который использует метод fetch для получения данных с сервера. Компонент «Продукты» получает «URL» в качестве реквизита. Внутри хука useEffect выполняется вызов fetch и обновляется состояние, которое затем отображает список извлеченных элементов.

const Products = ({ url }) => {
  const [data, setData] = useState();
  const [error, setError] = useState(false);

  useEffect(() => {
    fetch(url)
      .then(response => setData(response.data))
      .catch(error => setError(true))
  }, [url])

  if (!data) {
    return <p>No Products Found</p>
  }
  return (
    <>
      {
        data.map(item => <li key={item.id}>{item.name}</li>)
      }
    </>      
  )
}

Проблемы с приведенным выше кодом

Вышеупомянутый код будет работать отлично в большинстве случаев, но что, если компонент размонтируется или наш реквизит URL будет быстро меняться несколько раз? Например, если наш URL-адрес быстро изменится 3 раза, метод fetch будет вызываться 3 раза с 3 разными URL-адресами, и запросы будут занимать разное время, чтобы получить данные с сервера.

Итак, учитывая, что мы запускаем каждый запрос с разницей в 100 мс,

Первый запрос (для получения данных требуется 100 мс)
Выполняется при = 0 мс
Получает ответ при = 0 мс + 100 мс = 100 мс

Второй запрос (для получения данных требуется 500 мс)
Выполняется при = 100 мс
Получает ответ через = 100 мс + 500 мс = 600 мс

Третий запрос (возврат данных занимает 200 мс)
Выполняется при = 200 мс
Получает ответ через = 200 мс + 200 мс = 400 мс

Для приведенного выше примера через 100 мс мы вернем наш 1-й ответ. Затем через 400 мс придет третий ответ и, наконец, через 600 мс придет второй ответ. Таким образом, на самом деле, если мы запустим все эти 3 запроса на выборку, мы получим данные из второго, поскольку для их получения потребовалось немного больше времени. У нас есть данные по второму URL, а не по третьему, что означает, что наши данные не синхронизированы.

Это очень распространенный вариант использования, поскольку запросы в сети выполняются в разное время по разным причинам.

Решение проблемы

Чтобы избежать этого варианта использования, мы можем отменять запрос на выборку каждый раз, когда URL-адрес изменяется, используя функцию очистки useEffect, чтобы прервать запрос на выборку. Используя AbortController и передав сигнал контроллера в запросе на выборку, мы можем подключить AbortController к запросу на выборку. Затем просто в функции очистки мы можем вызвать функцию controller.abort(), чтобы отменить запрос при изменении URL-адреса. Таким образом, весь код внутри блоков then() и catch() вообще не будет выполняться.

Вот пример обновленного хука

  useEffect(() => {
    const controller = new AbortController()
    fetch(url, { signal: controller.signal })
      .then(response => setData(response.data))
      .catch(error => setError(true));
    
    return () => {
      controller.abort();
    }
  }, [url])

Заключение

Таким образом, независимо от того, сколько раз URL-адрес меняет данные, они будут синхронизированы с последним URL-адресом, потому что до того, как будет сделан новый вызов выборки, предыдущий полностью прерывается.

Спасибо и надеюсь, вам понравилось читать эту статью.