PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Оптимизация производительности React: memo, lazy, Suspense, Profiler

    Оптимизация производительности React: memo, lazy, Suspense, Profiler

    Аватар автора Оптимизация производительности React: memo, lazy, Suspense, Profiler

    Антон Ларичев

    Иконка календаря15 июня 2026
    ReactPerformanceOptimizationFrontendmiddleИконка уровня middle
    Картинка поста Оптимизация производительности React: memo, lazy, Suspense, Profiler

    Введение

    Производительность React-приложения напрямую влияет на пользовательский опыт и бизнес-метрики. Медленные рендеры, лишние перерисовки и тяжёлые бандлы делают интерфейс неотзывчивым. К счастью, React предоставляет встроенные инструменты для борьбы с этими проблемами: React.memo, React.lazy, Suspense и Profiler. В этой статье разберём, как и когда применять каждый из них, чтобы получить ощутимый прирост скорости без преждевременной оптимизации.

    Понимание этих API критично для middle-разработчика: они закрывают три ключевых вопроса — что рендерить, когда рендерить и сколько это занимает.

    React.memo: мемоизация компонентов

    React.memo — это HOC, который запоминает результат рендера компонента и пропускает повторный вызов, если пропсы не изменились. По умолчанию сравнение поверхностное (Object.is для каждого пропа).

    import { memo } from 'react';
    
    // Компонент отрендерится только при изменении пропсов
    const ProductCard = memo(function ProductCard({ title, price }) {
      console.log('Рендер ProductCard:', title);
      return (
        <div className="card">
          <h3>{title}</h3>
          <span>{price} ₽</span>
        </div>
      );
    });
    

    Если пропсы — объекты или функции, поверхностного сравнения недостаточно. Здесь помогают useMemo и useCallback в родителе:

    function ProductList({ items }) {
      // Стабильная ссылка на обработчик — иначе memo бесполезен
      const handleClick = useCallback((id) => {
        console.log('Клик:', id);
      }, []);
    
      return items.map((item) => (
        <ProductCard
          key={item.id}
          title={item.title}
          price={item.price}
          onClick={handleClick}
        />
      ));
    }
    

    Для сложных пропсов можно передать кастомный компаратор вторым аргументом:

    const Chart = memo(
      function Chart({ data, config }) {
        return <canvas />;
      },
      (prev, next) => {
        // Сравниваем только длину данных и тему
        return prev.data.length === next.data.length
          && prev.config.theme === next.config.theme;
      }
    );
    

    React.lazy и Suspense: код-сплиттинг

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

    import { lazy, Suspense } from 'react';
    
    // Чанк подгрузится только при первом рендере
    const Analytics = lazy(() => import('./Analytics'));
    const Editor = lazy(() => import('./Editor'));
    
    function Dashboard({ tab }) {
      return (
        <Suspense fallback={<Spinner />}>
          {tab === 'analytics' ? <Analytics /> : <Editor />}
        </Suspense>
      );
    }
    

    Suspense отображает запасной UI, пока чанк загружается. Можно вкладывать границы для гранулярного контроля состояний загрузки:

    function Page() {
      return (
        <Suspense fallback={<PageSkeleton />}>
          <Header />
          <Suspense fallback={<ContentSkeleton />}>
            <MainContent />
          </Suspense>
          <Suspense fallback={<SidebarSkeleton />}>
            <Sidebar />
          </Suspense>
        </Suspense>
      );
    }
    

    Для предзагрузки чанка по hover можно вызвать импорт заранее:

    const Modal = lazy(() => import('./Modal'));
    
    function OpenButton() {
      // Предзагружаем модалку при наведении
      const preload = () => import('./Modal');
      return <button onMouseEnter={preload}>Открыть</button>;
    }
    

    React Profiler: измерение рендеров

    Без измерений оптимизация — гадание. Profiler API позволяет программно собирать метрики рендеров в продакшене или в тестах.

    import { Profiler } from 'react';
    
    function onRender(id, phase, actualDuration, baseDuration, startTime, commitTime) {
      // actualDuration — время текущего рендера
      // baseDuration — оценка без мемоизации
      if (actualDuration > 16) {
        console.warn(`Медленный рендер ${id}: ${actualDuration.toFixed(2)}ms`);
      }
    }
    
    function App() {
      return (
        <Profiler id="ProductList" onRender={onRender}>
          <ProductList />
        </Profiler>
      );
    }
    

    В браузере используйте расширение React DevTools — вкладка Profiler показывает flame-граф рендеров, выделяет «прыгающие» компоненты и предлагает причины повторных вызовов. Запишите сценарий, найдите самые дорогие коммиты и работайте с ними в первую очередь.

    Частые ошибки

    • Мемоизация всего подряд. memo, useMemo и useCallback сами имеют цену — на сравнение и хранение. Оборачивайте только реально тяжёлые или часто перерисовываемые компоненты.
    • Нестабильные пропсы. Передача инлайн-объекта style={{ color: 'red' }} или массива items={[...]} ломает мемоизацию: ссылка меняется каждый рендер.
    • Один Suspense на весь экран. Это даёт «всё или ничего» — пользователь видит спиннер вместо частично готового интерфейса. Вкладывайте границы.
    • Оптимизация без замеров. Сначала Profiler, потом изменения. Иначе можно потратить часы на компонент, который рендерится раз в минуту.
    • Забыли про ключи в списках. Нестабильные key={index} сводят на нет любую мемоизацию дочерних элементов.

    Заключение

    React.memo, lazy, Suspense и Profiler — это базовый набор инструментов middle-разработчика для борьбы за производительность. Мемоизация убирает лишние рендеры, ленивая загрузка уменьшает бандл, Suspense управляет состояниями загрузки, а Profiler даёт объективные цифры. Главный принцип — измерять до и после, оптимизировать точечно и не превращать код в склад мемоизированных колбэков. Тогда приложение останется быстрым, а кодовая база — поддерживаемой.

    Иконка глаза3

    Комментарии

    0

    Постройте личный план изучения Основы React, React Router и Redux Toolkit до уровня Middle — бесплатно!

    Основы React, React Router и Redux Toolkit — часть карты развития Frontend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы разработки

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    бесплатно
    Подробнее
    изображение курса

    React Native и Expo Router

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Основы Swift и iOS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста React Hooks: полный гайд по useState, useEffect, useCallback, useMemo
    Иконка аватараАнтон
    Иконка календаря31 мая 2026
    ReactJavaScriptHooks+ 1middleИконка уровня middle

    React Hooks: полный гайд по useState, useEffect, useCallback, useMemo

    Полный гайд по React Hooks: useState, useEffect, useCallback и useMemo. Разбираем синтаксис, примеры использования и типичные ошибки.

    Иконка чипа+1
    Иконка глаза214
    Иконка комментариев0
    Картинка поста GraphQL с нуля: схемы, резолверы и интеграция с React
    Иконка аватараАнтон
    Иконка календаря14 июня 2026
    GraphQLReactApollo Client+ 2middleИконка уровня middle

    GraphQL с нуля: схемы, резолверы и интеграция с React

    GraphQL с нуля: разбираем схемы, резолверы и интеграцию с React через Apollo Client. Практические примеры запросов, мутаций и подписок.

    Иконка чипа0
    Иконка глаза44
    Иконка комментариев0
    Картинка поста Zustand vs Redux: что выбрать для React-проекта в 2025
    Иконка аватараАнтон
    Иконка календаря12 июня 2026
    ReactZustandRedux+ 1middleИконка уровня middle

    Zustand vs Redux: что выбрать для React-проекта в 2025

    Zustand vs Redux в 2025: подробное сравнение производительности, API, бойлерплейта и сценариев использования двух главных решений для управления состоянием в React.

    Иконка чипа0
    Иконка глаза74
    Иконка комментариев0
    Иконка чипа0