React: перерисовка компонентов при изменении размера окна

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

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

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

Для отслеживания изменений размеров окна браузера и эффективной перерисовки компонентов React, создайте обработчик события resize и примените хуки useState и useEffect для обновления состояния. Вот пример быстрого решения:

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

const useWindowSize = () => {
  const [size, setSize] = useState([window.innerWidth, window.innerHeight]);

  useEffect(() => {
    const resizeHandler = () => setSize([window.innerWidth, window.innerHeight]);
    window.addEventListener('resize', resizeHandler);
    return () => window.removeEventListener('resize', resizeHandler);
  }, []);

  return size;
};

function MyResponsiveComponent() {
  const [width, height] = useWindowSize();
  return <div>Ширина: {width}, Высота: {height}</div>;
}

Созданный нами хук useWindowSize инкапсулирует необходимую логику, упрощая тем самым отображение текущих размеров окна компонентами.

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

Ускорение работы с помощью метода отсечения вызовов

Используйте метод отсечения вызовов (debouncing) для улучшения производительности. Он позволяет уменьшить количество перерисовок при изменении размера окна, выполняя обновление состояния только после полного завершения серии изменений:

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

const useWindowSize = () => {
  const [size, setSize] = useState([window.innerWidth, window.innerHeight]);
  
  useEffect(() => {
    const debouncedResizeHandler = debounce(() => {
      setSize([window.innerWidth, window.innerHeight]);
    }, 100);

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

  return size;
};

Применение отсечения вызовов поможет заметно улучшить производительность.

Следование принципу DRY с помощью пользовательских хуков

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

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

export default function useWindowSize(){
  // ...тот же код, что и выше...
}

// MyResponsiveComponent.js
import useWindowSize from './useWindowSize';

function MyResponsiveComponent() {
  // ...используйте наш пользовательский хук...
}

Соблюдение принципа DRY упрощает поддержку кода.

Сохранение контекста при помощи стрелочных функций

Стрелочные функции помогут сохранить контекст this, когда вы создаёте обработчики событий, избавляя вас от необходимости применять bind:

jsx
Скопировать код
componentDidMount() {
  window.addEventListener('resize', this.handleResize);
}

handleResize = () => {
  // 'this' корректно привязано, проблем с контекстом не возникнет.
};

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

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

Изобразим, как React-компонент реагирует на изменение размера окна браузера, воспользовавшись аналогией с эволюцией:

Окно браузера:    🌐 Стандартный размер    --->    🌐 Увеличенный размер
React Компонент:       🐱‍👤                --->    🐱‍🚀
{класс и хук}
**Компонент-класс** с `componentDidUpdate`:             🚪🐱‍👤 → Изменился ли размер? → 🔄 → 🚪🐱‍🚀
**Функциональный компонент** с `useEffect` и `useState`: 🚪🐱‍👤 → Изменился ли размер? → 🪄 → 🚪🐱‍🚀

Так мы можем наглядно представить, как React-компоненты приспосабливаются к изменению размера окна.

Использование методов жизненного цикла React для компонентов-классов

При работе с классами реализуйте методы жизненного цикла для отслеживания изменений размера окна браузера:

jsx
Скопировать код
class MyResponsiveClassComponent extends React.Component {
  state = {
    width: window.innerWidth,
    height: window.innerHeight,
  };

  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  }

  handleResize = () => {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  };

  render() {
    return <div>Ширина: {this.state.width}, Высота: {this.state.height}</div>;
  }
}

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

Контроль за побочными эффектами при помощи useEffect

Хук useEffect — отличное средство управления побочными эффектами и предотвращения утечек памяти:

jsx
Скопировать код
useEffect(() => {
  // ...настроить обработчик изменения размера...
  return () => {
    // Аккуратное очистка — залог успешной работы.
    window.removeEventListener('resize', resizeHandler);
  };
}, []);

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

Управление перерисовкой путём изменения состояния

Контролируйте перерисовку компонентов, изменяя их состояние. Используйте setState или forceUpdate для реагирования на изменение размеров окна:

jsx
Скопировать код
this.setState({ width: window.innerWidth });
// или
this.forceUpdate();

Таким путём компонент будет обновлён и отреагирует на последние изменения размеров окна.

Получение данных о размере окна

Для получения текущих размеров окна, используйте свойства window.innerWidth и window.innerHeight:

jsx
Скопировать код
const width = window.innerWidth;
const height = window.innerHeight;

Благодаря этому можно легко реализовать адаптивные решения.

Улучшение кода с помощью CSS-медиа запросов

Дополните логику JavaScript по обработке изменения размеров использованием CSS-медиа запросов. Рассмотрите возможность совместного использования CSS и React для создания максимально адаптивного интерфейса.

Соблюдение приоритета производительности

Не забывайте об учете производительности при обработке изменения размеров. Оптимизируйте работу, применяя метод отсечения вызовов или управление вызовами (throttling).

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

  1. Строим адаптивные макеты с помощью React Hooks – LogRocket Blog — глубокое погружение в процесс создания адаптивных макетов в React.
  2. Использование хука Effect – React — официальное руководство React по использованию хука useEffect.
  3. Полное руководство по CSS-медиа запросам | CSS-Tricks — детальное изучение CSS-медиа запросов для адаптивного дизайна.
  4. Отсечение и управление вызовами в JavaScript — обзор техник оптимизации обработки событий изменения размера.
  5. useWindowSize React Hook – useHooks — пользовательский хук React для отслеживания изменений размера окна.
  6. Как использовать React.useMemo() — разъяснение применения хука useMemo для повышения производительности в React.