Решение ошибки 'window is not defined' в Next.js React

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

jsx
Скопировать код
// useEffect приходит на помощь!
import { useEffect } from 'react';

const SafeWindow = () => {
  useEffect(() => {
    // Здесь безопасно обращаться к объекту window
    console.log(window.location.href);
  }, []); // Эффект будет вызван однократно после монтирования

  return <div>Надёжный компонент — Window-Safe</div>;
};

export default SafeWindow;

Комбинация window и useEffect — ваш щит от ошибок «window not defined» в Next.js в процессе серверной отрисовки (SSR).

Кинга Идем в IT: пошаговый план для смены профессии

Как обойти ошибку с window в SSR

В огромном космосе Next.js код functionионирует как на сервере, так и на клиенте. window, как следует из названия, находится в доминионе клиента. На сервере его, понятное дело, нет, отсюда и возникает ошибка "Window is not defined".

Динамический импорт для модулей, специфичных для клиента

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

jsx
Скопировать код
import dynamic from 'next/dynamic';

const ClientSideComponent = dynamic(
  () => import('./ClientOnlyComponent'), // импортируем как промис
  { ssr: false } // отключаем серверный рендеринг
);
Подробнее об этом расскажет наш спикер на видео
skypro youtube speaker

Собственные хуки для контроля размеров окна

Хотите знать размеры окна браузера? Создадим пользовательский хук для этого!

jsx
Скопировать код
function useWindowSize() {
  const isClient = typeof window === 'object';

  function getSize() {
    return isClient ? { width: window.innerWidth, height: window.innerHeight } : { width: undefined, height: undefined };
  }

  const [windowSize, setWindowSize] = useState(getSize);

  useEffect(() => {
    if (!isClient) {
      return false;
    }
    
    function handleResize() {
      setWindowSize(getSize());
    }

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

  return windowSize;
}

Жизненные циклы и хуки: они стоят на страже доступа к window

componentWillMount отошёл в тень. Теперь роль "шерифов" исполняют useEffect и componentDidMount, обеспечивая надёжный доступ к window.

componentDidMount в классовых компонентах

Классовые компоненты используют метод componentDidMount как надежный барьер для безопасной работы с window.

jsx
Скопировать код
class SafeWindowComponent extends React.Component {
  componentDidMount() {
    console.log(window.innerHeight); //Здесь window находится под защитой
  }

  render() {
    return <div>Классовый компонент: работа с window осуществляется под надёжной защитой</div>;
  }
}

Функциональные компоненты и useEffect

В функциональных компонентах useEffect заменяет componentDidMount, componentDidUpdate и componentWillUnmount, объединяя их функции.

jsx
Скопировать код
import { useState, useEffect } from 'react';

const SafeWindowFunctional = () => {
  const [innerHeight, setInnerHeight] = useState(0);

  useEffect(() => {
    setInnerHeight(window.innerHeight); //Здесь можно работать без страха
    return () => {
      // Завершаем работу
    };
  }, []);

  return <div>Высота внутреннего окна — {innerHeight}px</div>;
};

Универсальные библиотеки и переделка компонентов

Код должен корректно functionировать как на сервере, так и на клиенте. При работе с window вы можете воспользоваться универсальными библиотеками — они работают в обоих случаях.

Переписываем компоненты с учётом window и SSR

Приведите компоненты в соответствие с особыми требованиями серверного рендеринга, чтобы они безопасно обращались к window.

jsx
Скопировать код
const MyComponent = () => {
  const isBrowser = typeof window !== 'undefined';

  if (isBrowser) {
    // Используем window
  }

  return (
    // Ваш JSX
  );
};

Визуализация

Воспринимайте window как свет, который присутствует только на улице.

JS
Скопировать код
if (typeof window !== 'undefined') {
  // На улице светло!
} else {
  // Мы в помещении
}

Next.js можно представить как здание с разными комнатами: серверной и клиентской частями.

Markdown
Скопировать код
Здание Next.js:
Серверная часть: `window` нет
Клиентская часть: `window` в наличии!

Убедитесь, что вы находитесь в подходящей комнате, прежде чем пользоваться window.

Сад кода Next.js

Как в саду, ваш код в Next.js требует грамотной "посадки" и заботы.

Правильно "сажаем" код, специфичный для клиента

Код для клиента следует располагать сообразно, чтобы он был функционален и его можно было легко поддерживать.

Регулярно очищаем память

Прислушиваетесь ли вы к событиям resize или scroll? После демонтирования компонента снимайте обработчики, чтобы освободить память для новых компонентов.

Условный рендеринг — ваш инструмент

Используйте условный рендеринг, чтобы компоненты соответствовали конкретному окружению выполнения и защищали от ошибок рендеринга на стороне клиента.

Полезные материалы

  1. Маршрутизация: страницы и компоновка | Next.js
  2. Window – Веб API | MDN
  3. Использование хука Effect – React
  4. Оптимизация: Ленивая загрузка | Next.js
  5. Проблемы и решения · vercel/next.js · GitHub
Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Какой хук позволяет безопасно обращаться к объекту window в функциональных компонентах Next.js?
1 / 5
Свежие материалы