Хабрахабр

[Перевод] Незнание основ React, которое, возможно, вас губит

Хотите получить наглядное представление о том, что происходит с компонентами, когда вы работаете с React? Читайте под катом перевод статьи Ohans Emmanuel, опубликованной на сайте freeCodeCamp.

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

В этой статье я попробую рассказать о некоторых принципах работы React, которые, по моему мнению, вам необходимо понимать.

Есть масса других статей, в которых рассматриваются такие понятия, как свойства компонента (props), состояние (state), контекст (context), изменение состояния компонента (setState) и прочие. Мы не будем разбирать эти принципы с технической точки зрения.

Я же хочу поговорить о том, что лежит в основе большинства технических операций, которые вы будете выполнять с React.

Готовы?

Скрытые процессы React

Первое, что каждый узнает в React, — это то, как создавать компоненты. Я уверен, что вы тоже этому учились.

Например:

// functional component function MyComponent() // class based component class MyComponent extends React.Component { render() { return <div> My Class Component </div> }
}

Большая часть компонентов, которые вы прописываете, возвращает вам некоторые элементы.

function MyComponent() { return <span> My Functional Component </span> //span element
} class MyComponent extends React.Component { render() { return <div> My Class Component </div> //div element }
}

Изнутри этот процесс выглядит так: большинство компонентов возвращают дерево элементов.

После внутренней оценки компоненты часто возвращают дерево элементов

Кроме того, вы наверняка помните, что компоненты работают как функции, возвращающие значения на основании своих значений props и state.

Компоненты — это что-то вроде функций с параметрами props и state

Следовательно, всякий раз, когда значения свойств (props) и состояния (state) компонента меняются, создается новое дерево элементов.

В результате появляется новое дерево элементов Если значения props или state меняются, дерево элементов перерисовывается.

Если компонент основан на наследовании классов, дерево элементов возвращает функция

<code>render</code>. <source lang="javascript">class MyComponent extends React.Component { render() { //this function is invoked to return the tree of elements }
}

Если же компонент функциональный, его возвращаемое значение дает дерево элементов.

function MyComponent() { // the return value yields the tree of elements return <div> </div>
}

Почему это важно?

Рассмотрим компонент <MyComponent />, который принимает prop, как показано ниже.

<MyComponent name='Ohans'/>

Рендеринг этого компонента возвращает дерево элементов.


Дерево элементов, возвращаемое после перерисовки <MyComponent />

Что происходит, когда значение name меняется?

<MyComponent name='Quincy'/>

Ну, возвращается новое дерево элементов!


НОВОЕ дерево элементов, возвращаемое после перерисовки <MyComponent /> с другими props

Хорошо.
Теперь в распоряжении React два разных дерева — предыдущее и текущее дерево элементов.
На этом этапе React сравнивает оба дерева, чтобы найти изменения.

Что же именно изменилось?
Два разных дерева.

Дерево не изменилось полностью, а лишь частично обновилось (так происходит в большинстве случаев).

После сравнения React обновляет фактический DOM с учетом изменений в новом дереве элементов.

Все просто, не так ли?

Мы с вами смогли разобрать этот процесс, несмотря на то что он достаточно сложный. Сравнение двух деревьев на предмет изменений называется «согласование».

React обновляет только необходимое, правда?

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


Из React Docs: инспектор DOM, показывающий детали обновления

Все ли так?

Все так.

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

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

Это, конечно, правда, но проблемы с производительностью большинства приложений на React начинаются еще до обновления DOM!

Ненужный рендеринг vs визуальные обновления

Даже если дерево элементов компонента маленькое, его рендеринг занимает некоторое время (хотя бы незначительное). Чем больше дерево элементов компонента, тем больше времени занимает рендеринг.

Это значит, что перерисовка деревьев элементов компонентов вашего приложения с React будет лишней, если она НЕ необходима.

Позвольте мне показать это на простом примере.

Представьте себе приложение со структурой компонентов, как на иллюстрации ниже.


Приложение с родительским компонентом A и дочерними компонентами B, C и D

Однако делается это только для того, чтобы передать это свойство компоненту D. Общий компонент-контейнер A получает определенное свойство.


Родительский компонент A получает некоторые свойства и передает их дальше дочернему компоненту D

Теперь, когда изменяется значение свойства в компоненте A, все дочерние элементы A перерисовываются для вычисления нового дерева элементов.



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

Они не получили никаких новых свойств! Соответственно, компоненты B и С также повторно рендерятся, даже если они не изменились вообще!

Эта лишняя перерисовка и есть ненужный рендеринг.

В этом примере компоненты B и C перерисовывать не нужно, но React об этом не знает.

Есть много способов решить эту проблему, и я описывал их в моей недавней статье How to Eliminate React Performance Issues («Как минимизировать проблемы производительности React»).

Посмотрите на приложение ниже. Идем дальше.


Cardie в действии 🙂

Я назвал это приложение Cardeу.

Когда я нажимаю кнопку, чтобы изменить профессию пользователя, я могу выбрать выделение обновлений для DOM, как показано ниже.


Активируйте визуальное отображение обновлений (Paint Flashing) с помощью Chrome DevTools

Теперь мне видно, что было обновлено в DOM.

Обратите внимание на зеленую подсветку вокруг текста I am a Librarian («Я библиотекарь».) Это визуальный способ отмечать элементы, которые нужно обновить в DOM.

Это все здорово, конечно, но меня беспокоит исходный рендеринг дерева элементов компонентов React.

Я могу проверить и его.


Поставьте галочку в React DevTools, чтобы включить подсветку обновляемых элементов

Теперь я вижу, какие компоненты перерисовываются на самом деле, когда я нажимаю эту кнопку.


Обратите внимание на зеленую подсветку вокруг карты пользователя

Вы видите, насколько отличаются визуальный способ отмечать элементы, которые нужно обновить в DOM, и обновления рендеринга, которые проводит сам React?

React перерисовывает всю карту пользователя, а обновляется только короткий текст.

И это важно.

Заключение

Думаю, что теперь у вас появилось более наглядное представление о том, что и как происходит с вашими компонентами в React.

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

Вперед — к созданию крутых приложений!

Если да, у меня есть отличная серия книг, посвященная Redux. Учитесь работать с React/Redux? Некоторые говорят, что это лучшая техническая литература, которую они читали!

Показать больше

Похожие публикации

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

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

Кнопка «Наверх»