Теперь, когда был официально выпущен долгожданный React Hooks API, я наконец смог избавиться от желания сравнивать скорость его выполнения по сравнению со старыми добрыми HOC. И результаты меня удивили!

Среди всего ажиотажа по поводу блестящих новых крючков, верный старый HOC, возможно, был без надобности поносить. Сразу скажу, что мои простые тесты показали, что HOC все еще может быть быстрее, несмотря на «ад обертки», за который его в последнее время много ругают. Конечно, если вы обнаружите, что мой тест ошибочен, я буду благодарен за исправление.

Тестовое приложение

Я придумал базовое тестовое приложение, которое визуализирует 10 000 экземпляров функционального компонента, имеющего 3 значения состояния, и эффект, который устанавливает эти 3 значения состояния один раз после первого рендеринга. Главный компонент регистрирует время, прошедшее с момента создания корневого компонента до момента завершения рендеринга 10 000 элементов. Для этого также используется эффект.

Затем я создал две версии тестового приложения, одну с использованием хуков, а другую с использованием HOC (используя недавно опубликованную мной Reactor Library: «https://github.com/arnelenero/reactorlib#reactor- библиотека").

Версия с крючками

import React, { useEffect, useState } from 'react';
import { render } from 'react-dom';
const array = [];
for (let i = 0; i < 10000; i++) array[i] = true;
const Component = () => {
  const [a, setA] = useState('');
  const [b, setB] = useState('');
  const [c, setC] = useState('');
  
  useEffect(() => {
    setA('A');
    setB('B');
    setC('C');
  }, []);
  return <div>{a + b + c}</div>;
};
const Benchmark = ({ start }) => {
  useEffect(() => {
    console.log(Date.now() - start);
  });
  return array.map((item, index) => <Component key={index} />);
};
render(<Benchmark start={Date.now()} />, document.getElementById('root'));

Версия HOC (Reactor Library)

import React from 'react';
import { render } from 'react-dom';
import { compose, withState, withEffect } from '@reactorlib/core';
const array = [];
for (let i = 0; i < 10000; i++) array[i] = true;
const _Component = ({ a, b, c }) => {
  return <div>{a + b + c}</div>;
};
const Component = compose(
  withState({
    a: '',
    b: '',
    c: ''
  }),
  withEffect(({ setA, setB, setC }) => {
    setA('A');
    setB('B');
    setC('C');
  }, true)
)(_Component);
const _Benchmark = () => {
  return array.map((item, index) => <Component key={index} />);
};
const Benchmark = compose(
  withEffect(({ start }) => {
    console.log(Date.now() - start);
  })
)(_Benchmark);
render(<Benchmark start={Date.now()} />, document.getElementById('root'));

Тестовая установка

Тесты проводились на Macbook 12 начала 2015 года (1,1 ГГц Core M, 8 ГБ ОЗУ) под управлением MacOS Sierra 10.12.3 и Chrome 71.

Обе версии находятся на React 16.8.1.

Результаты испытаний

Я зафиксировал результаты 10 тестовых прогонов в MacOS Chrome, и все они показали явный победитель.

Rendering Time in milliseconds
Run#     Hooks        HOCs
-----------------------------
 1       2197         1440
 2       2302         1757
 3       2749         1407
 4       2243         1309
 5       2167         1644
 6       2219         1516
 7       2322         1673
 8       2268         1630
 9       2164         1446
10       2071         1597

Но не верьте мне на слово. Вы можете запустить две версии, которые я опубликовал выше, и убедиться в этом сами.

Заключение

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

Прочие соображения

Выбор между Hooks и HOC может оказаться нелегким делом, как мы изначально думали. Помимо того, что я здесь рассмотрел, есть и другие факторы, которые влияют на этот выбор, например ваша конкретная стратегия повторного использования кода. Хорошо, что нас не заставляют выбирать только одно из них; мы можем использовать оба, тщательно рассуждая, какие компоненты должны предпочесть один другому.

В местах, где вместо этого вам понадобятся HOC, вы можете проверить мою библиотеку Reactor (https://github.com/arnelenero/reactorlib#reactor-library). Нет, дело не только в функциональных компонентах; в нем есть много других вещей, которые могут помочь вам упростить разработку на React / Redux. Не стесняйтесь использовать, это ваше столько же, сколько и мое.