Следующие 14 ошибок гидратации при использовании пользовательского хука isMobile

В течение долгого времени я использую собственный крючок реагирования под названием useIsMobile, который возвращает true, если область просмотра имеет определенную ширину. Я использовал этот крючок во всех своих проектах, и у меня никогда не было с ним проблем.

Недавно я начал новый проект, используя Next 14, и начал получать эту ошибку: Error: Text content does not match server-rendered HTML. See more info here: https://nextjs.org/docs/messages/react-hydration-error

После некоторой отладки я понимаю, что проблема связана с моим специальным хуком. Когда я использую перехватчик, сервер сначала отправляет «мобильную версию», но клиент отображает «версию для настольного компьютера» так, как должен, и создает разницу между деревом реагирования, которое было предварительно визуализировано с сервера, и деревом реагирования, которое было визуализировано во время первого рендеринга.

Эта проблема сохраняется, даже если я использую «использовать клиент». Я также заметил, что иногда ошибка может быть вызвана медиазапросами CSS или может быть полностью проигнорирована.

Кто-нибудь еще сталкивался с этой проблемой? Кто-нибудь знает, как я могу это исправить?

Это крючок, который я использую:

'use client';
import { useState, useEffect } from 'react';

const useWindowSize = () => {
  const [windowSize, setWindowSize] = useState({
    width: typeof window !== 'undefined' ? window?.innerWidth : null,
    height: typeof window !== 'undefined' ? window?.innerHeight : null,
  });

  useEffect(() => {
    const handleResize = () => {
      if (typeof window !== 'undefined') {
        setWindowSize({
          width: window?.innerWidth,
          height: window?.innerHeight,
        });
      }
    };

    window?.addEventListener('resize', handleResize);

    handleResize();

    return () => window?.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
};

export default useWindowSize;
'use client';
import { useState, useEffect } from 'react';
import useWindowSize from './useWindowSize';

const useIsMobile = (breakpoint: number = 768): boolean => {
  const { width } = useWindowSize()!;
  const [isMobile, setMobile] = useState<boolean>(
    width! <= (breakpoint || 768)
  );

  useEffect(() => {
    setMobile(width! <= (breakpoint || 768));
  }, [width, breakpoint]);

  return isMobile;
};

export default useIsMobile;
  const isMobile = useIsMobile(500);

  return (
    <div className = {styles.nav}>
      {!isMobile && <div className = {styles.logo}>Logo</div>}
Поведение ключевого слова "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) для оценки ваших знаний,...
2
0
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решение состоит в том, чтобы приостановить рендеринг элемента до тех пор, пока клиентская сторона не оценит ширину устройства.

'use client';
import { useState, useEffect, useLayoutEffect } from 'react';
import useWindowSize from './useWindowSize';

const useIsMobile = (breakpoint = 768) => {
  const { width } = useWindowSize();
  const [isMobile, setMobile] = useState(null);  // starts as null to indicate no initial assumption

  useLayoutEffect(() => {
    if (width !== null) {
      setMobile(width <= breakpoint);
    }
  }, [width, breakpoint]);

  return isMobile;
};

export default useIsMobile;

Затем в своем компоненте вы можете условно отображать контент в зависимости от того, был ли определен isMobile:

const isMobile = useIsMobile(500);

if (isMobile === null) {
  return <div>Loading...</div>;
}

return (
  <div className = {styles.nav}>
    {!isMobile && <div className = {styles.logo}>Logo</div>}
  </div>
);

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