Оптимизация React-приложения: Display:’none’ или перерендер

от автора

Небольшое практическое исследование было вдохновлено статьей https://itnext.io/using-css-to-speed-up-your-react-apps-a26470829472, а конкретно следующим отрывком (перевод мой):

Hiding instead of unmounting

Представьте, что у вас есть 2 вкладки. При переключении между ними стандартными методами “React” происходит размонтирование “таба из” и монтирование “таба в”. … пример из Твиттера …

Ответ кроется в React runtime. Каждый раз при монтировании нового компонента, React должен создать virtual DOM (связанный список всех подкомпонентов внутри смонтированного дерева),выполнить всю логику внутри каждого из компонентов (или deprecated componentWillMount ) и затем добавить компоненты в DOM. В то же время, React должен размонтировать предыдущий компонент,что означает — свернуть virtual DOM, прогнать componentWillUnmount и затем удалить соответствующие элементы из DOM.

Возможно, это окажется сюрпризом, но размонтирование — не дешевая операция. Вы можете подумать, что это просто удаление, но React должен удалить рефы из многих участков virtual DOM и прогнать жизненные циклы всех компонентов, которые будут отмонтированы (unmounted). Это может происходить не быстро. До времен React Fiber (перед React 15.x.x.) размонтирование предыдущего и монтирование следующего компонента было последовательным. Нынче, React производит это параллельно для экономии времени, с учетом того, что эти процессы не зависят друг от друга.

Фокус в том,чтобы не заставлять React монтировать\размонтировать,а использовать CSS для показа\скрытия содержимого табов.

Дальше было про тот же пример из Твиттера и то, что при таком подходе к разработке — DOM дерево может слишком разрастись. Как разработчик приложения, которое потенциально может генерировать очень много компонентов и огромное количество табов (и человек, получивший задачу разобраться — а не будет ли это хорошей оптимизацией))) — я решил написать простой код для проверки этой теории и соотвественно последствий:

import './App.css'; import uniqid from 'uniqid'; import React,{useState} from 'react';  function App() {   const [tab, setTab] = useState(true)    const Row = (quantity, bColor) => {     const result = []     for (let i =0; i< quantity; i+=1){     result.push(<div key={uniqid + i} style={{height: '30px', width: '200px', border:'1px solid '+ bColor }}>Row {i} Tab {tab?1:2}</div>)   }     return result }; const handleClick = () => {   console.log(tab)   setTab(tabState=>!tabState) }    return (     <div className="App">       <button type='button' onClick={handleClick}>Вкладка {tab?1:2}</button>       <div style={{height: '300px', width: '300px', overflow:'auto', border:'1px solid gray', margin: '0 auto' }}>     {/* { <ul>       {tab && Row(50000, 'tomato')} */}     { <ul style={{display:!tab?'none':'block'}}>        {Row(50000, 'tomato')}     </ul>}      {/* { <ul>        {!tab && Row(50000, 'green')} */}     { <ul style={{display:tab?'none':'block'}}>       {Row(50000, 'green')}     </ul>}     </div>     </div>   ); }  export default App;

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

Как это работает, уверен, каждый в состоянии проверить сам, так что перейду сразу к выводам:

  1. в случае с работой через React-way у меня на ноутбуке переключение между табами составляет от 7 до 10 секунд

  2. в случае с работой через скрытие display:none\display:block — переключение от 1.5 до 2.5 секунд

Казалось бы вопросы сняты — можно пользоваться, но давайте посмотрим на выделение памяти для chrome.exe(для win10 — это найти через поиск «монитор ресурсов»):

  1. потребление памяти находится в рамках 600-1200мб в случае с рендером методами React

  2. от 1800 до 3200мб в случае со скрытием табов через стили

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


ссылка на оригинал статьи https://habr.com/ru/post/691414/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *