Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Композиция компонентов JS: React Hooks

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

В этом уроке мы разберем несколько приемов построения компонентов, которые помогут избежать проблем с оптимизацией не прибегая к memo.

Пример ниже состоит из двух компонентов, в котором при изменении состояния в одном компоненте отрисовывается дочерний:

import { useState, useEffect } from 'react';

const Greeting = () => {
  useEffect(() => {
    console.log(`Компонент Greeting отрисован в ${new Date().toLocaleTimeString()}`);
  });

  return <h3>Hello, world!</h3>;
};

const App = () => {
  const [name, setName] = useState('');
  return (
    <>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <Greeting />
    </>
  );
};

Чтобы избежать лишнего рендера Greeting, достаточно убрать из App состояние. Этого можно добиться выделением дополнительного компонента:

import { useState, useEffect } from 'react';

const Form = () => {
  const [name, setName] = useState('');

  return <input value={name} onChange={(e) => setName(e.target.value)} />
};

const Greeting = () => {
  useEffect(() => {
    console.log(`Компонент Greeting отрисован в ${new Date().toLocaleTimeString()}`);
  });

  return <h3>Hello, world!</h3>;
};

const App = () => {
  return (
    <>
      <Form />
      <Greeting />
    </>
  );
};

Может показаться, что это усложнило приложение из-за добавления еще одного компонента. Но на самом деле такой код лучше описывает архитектуру. Состояние теперь выделено там, где используется, нет компонентов, которые бы перерисовывались без необходимости при изменении состояния.

Такой подход не всегда может работать, разберем это на другом примере:

import { useState, useEffect } from 'react';

const Greeting = () => {
  useEffect(() => {
    console.log(`Компонент Greeting отрисован в ${new Date().toLocaleTimeString()}`);
  });

  return <h3>Hello, world!</h3>;
};

const App = () => {
  const [name, setName] = useState('');
  return (
    <div data-name={name}>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <Greeting />
    </div>
  );
};

Здесь мы не можем выделить состояние так же, как в предыдущем случае, потому что родительский элемент тоже использует состояние. Так не получится сделать:

<div data-name={name}>
  <Form />
  <Greeting />
</div>

Однако выход есть, и он достаточно простой:

import { useState, useEffect } from 'react';

const Form = ({ children }) => {
  const [name, setName] = useState('');

  return (
    <div data-name={name}>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      {children}
    </div>
  );
};

const Greeting = () => {
  useEffect(() => {
    console.log(`Компонент Greeting отрисован в ${new Date().toLocaleTimeString()}`);
  });

  return <h3>Hello, world!</h3>;
};

const App = () => {
  return (
    <Form>
      <Greeting />
    </Form>
  );
};

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

Такой простой способ позволяет изолировать состояние от компонентов, которые не зависят от него. Прежде чем использовать memo, лучше рассмотреть этот подход. Он более выгоден, так как позволяет выстроить правильную композицию приложения.


Дополнительные материалы

  1. React re-renders guide: everything, all at once

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 9 мая
профессия
от 9 900 ₽ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 9 мая

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»