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 даёт объективные цифры. Главный принцип — измерять до и после, оптимизировать точечно и не превращать код в склад мемоизированных колбэков. Тогда приложение останется быстрым, а кодовая база — поддерживаемой.

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

    Комментарии

    0

    Постройте личный план изучения Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid до уровня Middle — бесплатно!

    Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid — часть карты развития Frontend

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

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

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

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

    Vue 3 и Pinia

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

    Nuxt

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

    Feature-Sliced Design

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

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

    Картинка поста Vue vs React в 2026: какой фреймворк выбрать для проекта
    Иконка аватараАнтон
    Иконка календаря10 сентября 2026
    VueReactFrontend+ 1middleИконка уровня middle

    Vue vs React в 2026: какой фреймворк выбрать для проекта

    Сравниваем Vue и React в 2026 году: реактивность, Composition API vs хуки, Server Components и Vapor Mode на примерах кода.

    Иконка чипа0
    Иконка глаза122
    Иконка комментариев0
    Картинка поста React useState и useEffect: полное руководство 2024
    Иконка аватараАнтон
    Иконка календаря29 июля 2026
    ReactuseStateuseEffect+ 3juniorИконка уровня junior

    React useState и useEffect: полное руководство 2024

    Разбираем useState и useEffect с нуля: как управлять состоянием и побочными эффектами в React-компонентах с реальными примерами.

    Иконка чипа0
    Иконка глаза1 101
    Иконка комментариев0
    Картинка поста Вопросы на собеседовании Junior Frontend: разбор с примерами кода
    Иконка аватараАнтон
    Иконка календаря13 сентября 2026
    frontendjavascriptсобеседование+ 2juniorИконка уровня junior

    Вопросы на собеседовании Junior Frontend: разбор с примерами кода

    Собеседование Junior Frontend: вопросы по JavaScript, CSS, DOM и асинхронности с примерами кода и разбором частых ошибок кандидатов.

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