Как сделать чтобы useFetch отрабатывал только на клиенте

Ответ

В Next.js можно использовать useEffect для выполнения запроса только на клиенте. Также можно проверить, выполняется ли код на клиенте через typeof window !== 'undefined'.

Пример с хуком useFetch:

import { useEffect, useState } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (typeof window !== 'undefined') { // Проверка на клиент
      fetch(url)
        .then(res => res.json())
        .then(data => {
          setData(data);
          setLoading(false);
        });
    }
  }, [url]);

  return { data, loading };
}

Альтернативный вариант - использовать useState с условием:

const [mounted, setMounted] = useState(false);

useEffect(() => {
  setMounted(true);
}, []);

// Затем использовать mounted в условиях запроса

Это предотвратит выполнение запроса во время SSR.

Ответ 18+ 🔞

Ах ты ж ёпта, ну и намудрили же эти ребята из Next.js с этим SSR! Сидишь такой, пишешь код, а он тебе на сервере пытается fetch запустить, а там window-то, блядь, нету! Ну как так-то, а? Это ж надо догадаться — в рот меня чих-пых!

Смотри, вот тебе рабочий способ, чтоб твой useEffect не выёбывался на сервере. Берёшь и проверяешь, не в окне ли мы, блядь, находимся:

import { useEffect, useState } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (typeof window !== 'undefined') { // Проверка на клиент
      fetch(url)
        .then(res => res.json())
        .then(data => {
          setData(data);
          setLoading(false);
        });
    }
  }, [url]);

  return { data, loading };
}

Вот видишь? typeof window !== 'undefined' — это как спросить: «Э, братан, а мы вообще в браузере?». Если нет — сиди, молчи, не высовывайся, запрос не делай. А то сервер тебе ебальник свернёт, он же не понимает, что такое fetch в своей песочнице!

А есть ещё, блядь, вариант с mounted — типа флажок поставил, что компонент уже на клиенте ожил:

const [mounted, setMounted] = useState(false);

useEffect(() => {
  setMounted(true);
}, []);

// Затем использовать mounted в условиях запроса

Типа сначала mounted — false, компонент на сервере рендерится, запросы не летят. Потом приехал на клиент, useEffect сработал, флажок поднял — и теперь можно уже и данные тянуть, не стесняясь.

В общем, суть в том, чтобы не делать запросы, пока ты на сервере, а то будет тебе, как Герасиму с Муму — бросишь не в ту воду, и потом совесть заебает. Так что проверяй окружение, ёпта, и будет тебе счастье!