Render props и HOC (обзор)

Обзорный урок про два «классических» паттерна переиспользования логики — render props и HOC — и про то, почему сегодня их чаще заменяют кастомные хуки.

Render prop — проп-функция, которой компонент передаёт свои данные, чтобы вызывающий сам решил, что отрисовать. HOC (higher-order component) — функция, которая принимает компонент и возвращает новый, обёрнутый.

Зачем это было нужно

До хуков (React < 16.8) не было способа переиспользовать логику с состоянием между компонентами. Render props и HOC появились именно для этого: «поделиться» подпиской, загрузкой данных, отслеживанием мыши без копипаста. Сегодня ту же задачу решают кастомные хуки — короче и без вложенности, — но эти паттерны живут в множестве библиотек, поэтому их важно узнавать.

Render props

Компонент инкапсулирует логику и вызывает функцию-проп (часто children как функцию), передавая ей результат. Что рисовать — решает потребитель.

function MouseTracker({ children }) {
  const [pos, setPos] = React.useState({ x: 0, y: 0 });
  return (
    <div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
      {children(pos)}
    </div>
  );
}

// потребитель сам решает, как отрисовать координаты
<MouseTracker>
  {(pos) => <p>Курсор: {pos.x}, {pos.y}</p>}
</MouseTracker>

Плюс — гибкость, минус — «пирамида» вложенных функций при нескольких таких компонентах (callback hell в JSX).

HOC — компонент высшего порядка

HOC — функция withX(Component) => EnhancedComponent. Она оборачивает компонент, добавляя ему пропсы или поведение. По соглашению имя начинается с with.

function withUser(Component) {
  return function Wrapped(props) {
    const user = useCurrentUser(); // некий источник данных
    return <Component {...props} user={user} />;
  };
}

const ProfileWithUser = withUser(Profile);

Минусы HOC: «обёрточный ад» в дереве компонентов, коллизии имён пропсов, неочевидно, откуда пришёл проп. Поэтому react-redux, например, перешёл с HOC connect на хуки useSelector/useDispatch.

Сравнение подходов

ПаттернКак переиспользует логикуГлавный минус
Render propsпроп-функция получает данныевложенность функций в JSX
HOCобёртка добавляет пропсы«обёрточный ад», скрытые пропсы
Кастомный хуквызов функции use… в телепочти нет — предпочтительный способ

Что выбирать сегодня

Для новой переиспользуемой логики берите кастомный хук — он плоский и явный. Render props и HOC оставьте для случаев, где нужно управлять самой отрисовкой извне (render prop) или встроиться в API существующей библиотеки (HOC). Узнавать их в чужом коде обязательно.

Итог

  • Render props и HOC — доходулевые способы делиться логикой с состоянием.
  • Render prop отдаёт данные функции-пропу; HOC оборачивает компонент.
  • Минусы — вложенность и «обёрточный ад»; кастомные хуки их устраняют.
  • Для новой логики выбирайте хуки; паттерны нужно уметь читать в чужом коде.
Проверьте себя
1. Что такое render prop?
AПроп со строкой-классом
BПроп-функция, которой компонент передаёт данные, чтобы вызывающий решил, что отрисовать
CHTML-атрибут React
DХук для рендера
2. Что делает HOC (higher-order component)?
AПринимает компонент и возвращает новый, обёрнутый
BСоздаёт контекст
CЗапускает эффекты
DСортирует пропсы
3. Чем кастомные хуки лучше render props и HOC для НОВОЙ логики?
AОни работают в классах
BОни плоские и явные — без вложенности функций и «обёрточного ада»
CОни быстрее любого кода
DОни не требуют импорта
Поддержать проект