Как обернуть компонент React с небольшим штрафом за производительность?

Моя команда использует библиотеку React MaterialUI. Чтобы обеспечить согласованный шаблон пользовательского интерфейса и упростить настройку компонента MaterialUI, мы переносим каждый компонент MaterialUI в наш собственный компонент. Например:

const style = {} // our project custom style for ListItemText
const OurListItemText = ({primary, secondary, classes}: Props) => (
  <MuiListItemText
    primary={primary}
    secondary={secondary}
    className={classes.text}
  />
) // we only expose primary and secondary props of the original MuiListItemText.
// Team members are blocked from customising other MUIListItemText props

export default withStyles(styles)(OurListItemText)

MuiListItemText - это оригинальный компонент MaterialUI, а OurListItemText - наш компонент оболочки. В нашем проекте разрешено использовать только OurListItemText.

В качестве фрагмента выше, OurListItemText ничего не делает, кроме как перенаправить реквизиты в MuiListItemText. Однако это сильно влияет на производительность:

React Flame graph

ListItemText в верхней части находится в OurListItemText а ниже - MuiListItemText. Если мы используем MuiListItemText напрямую, это может быть на 50% быстрее (мы попытались), что заметно, когда у нас есть 100 ListItemText. Удаление withStyles HOC немного улучшается, но не значительно.

ListItemText - только один пример, у нас есть аналогичная проблема с производительностью для других упакованных компонентов. (2 Typography на графике выше - это еще одна пара нашего компонента-обертки и MUI-оригинал-компонента)

Как улучшить производительность этих простых компонентов реквизита-пересылки?

Ответ 1

упаковка компонента React добавляет один дополнительный уровень полного жизненного цикла React (т.е. необходимо установить оболочку). Можно ли это избежать?

Вы можете избежать жизненных циклов, избегая JSX и напрямую вызывая функции.
Например.

{Component({ data: 1, children: 'Hello' })}

вместо

<Component data={1}>Hello</Component>

Это сообщение в блоге утверждало, что он улучшил скорость на 45% со своим тестовым случаем.

Однако этот синтаксис может быть не столь читабельным и понятным.

Некоторые цитаты из Дана Абрамова по этому вопросу:

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

Обратите внимание: если вы не создаете тысячи элементов, разница в производительности не будет заметна. Кроме того, если ваши компоненты не очень плоские и простые, "чистая победа" от этой оптимизации, вероятно, будет гораздо менее актуальной на практике.

Я бы не стал дожидаться, пока Prepack сделает оптимизацию, хотя временная шкала неясна, и результирующая оптимизация может быть не такой.

Что касается значимости улучшения производительности, это будет зависеть от вашего проекта, и единственный способ быть уверенным в том, чтобы попробовать и увидеть улучшение для себя.

Ответ 2

Если вам нужна сырая производительность - не оберните ListItem, а напишите вместо этого свою замену

Источник элемента списка не имеет никаких дополнительных зависимостей, поэтому Ctrl-C, Ctrl-V будет работать

Затем отрегулируйте свои потребности, удалите код, который вам не нужен, и т.д....

Это гарантирует максимальную производительность


Отрицательная сторона - стоимость поддержки будет расти.