Reactdom render что это
Перейти к содержимому

Reactdom render что это

  • автор:

Reactdom render что это

Мельчайшими блоками приложения React являются элементы. Определение простейшего элемента:

const element = 

Hello, React

;

По сути элементы в React — это обычные объекты JavaScript, с которыми быстрее работать, чем с обычными элементами на веб-странице.

Для рендеринга элементов в React вначале необходимо определить корневой элемент, в который будет производиться рендеринг. Для этого применяется метод ReactDOM.createRoot() . В него передается элемент веб-страницы, в котором будет производиться рендеринг

const rootNode = document.getElementById("app"); // элемент для рендеринга приложения React // получаем корневой элемент const root = ReactDOM.createRoot(rootNode);

Здесь константа rootNode представляет некоторый элемент html-страницы с id=»app» . И в данном случае именно в этот элемент будет производиться рендеринг приложения React. Результатом метода ReactDOM.createRoot является объект ReactDOMRoot (в данном случае он представлен константой root ), который представляет указатель на структуру данных, которую инфраструктура React использует для отслеживания дерева элементов для рендеринга.

Непосредственно для рендеринга у объекта ReactDOMRoot вызывается метод render() . В этот метод передается компонент, который мы хотим отобразить на веб-странице. Например, рендеринг заголовка.

root.render( 

Hello React

, // элемент, который мы хотим создать )

Элемент React может иметь только один корневой элемент, в который уже вкладываются все остальные элементы. Например, создадим новый проект. Определим в проекте следующий файл index.html :

ReactElement и элементы в React

В данном случае корневым элементом является , который будет добавляться на веб-страницу в элемент с >

При этом в один элемент DOM можно добавить только один элемент ReactElement, например, добавим еще один элемент на веб-страницу:

Рендеринг элементов в React

Обновление элементов

Элементы React являются неизменяемыми (immutable). После создания элемента нельзя изменить его атрибуты или дочерние элементы. И единственный способ изменить интерфейс, определенный в элементе, это создать новый элемент и передать его в функцию ReactDOM.render(). Например:

    METANIT.COM        

ReactElement и рендеринг и обновление элементов в React

В данном случае в элементе с будет отображаться текущее время, однако, чтобы каждую секунду изменялось отображаемое значение, там надо повторно вызывать функцию для элемента.

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

Немного о том, как работает виртуальный DOM в React

image

DOM расшифровывается как Document Object Model (объектная модель документа). Проще говоря, DOM — это представление пользовательского интерфейса (user interface, UI) в приложении. При каждом изменении UI, DOM также обновляется для отображения этих изменений. Частые манипуляции с DOM негативно влияют на производительность.

Что делает манипуляции с DOM медленными?

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

Манипуляции с DOM являются сердцем современного интерактивного веба. К сожалению, они намного медленнее большинства JavaScript-операций. Ситуация усугубляется тем, что многие JavaScript-фреймворки обновляют DOM чаще, чем необходимо.

Допустим, у нас имеется список из 10 элементов. Мы изменяем первый элемент. Большинство фреймворков перестроят весь список. Это в 10 раз больше работы, чем требуется! Только 1 элемент изменился, остальные 9 остались прежними.

Перестроение списка — это легкая задача для браузера, но современные веб-сайты могут осуществлять огромное количество манипуляций с DOM. Поэтому неэффективное обновление часто становится серьезной проблемой. Для решения данной проблемы команда React популяризовала нечто под названием виртуальный (virtual) DOM (VDOM).

Виртуальный DOM

В React для каждого объекта настоящего DOM (далее — RDOM) существует соответствующий объект VDOM. VDOM — это объектное представление RDOM, его легковесная копия. VDOM содержит те же свойства, что и RDOM, но не может напрямую влиять на то, что отображается на экране.

Виртуальный DOM (VDOM) — это концепция программирования, где идеальное или «виртуальное» представление UI хранится в памяти и синхронизируется с «реальным» DOM, используемая такими библиотеками, как ReactDOM. Данный процесс называется согласованием (reconcilation).

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

Почему VDOM является более быстрым?

Когда в UI добавляются новые элементы, создается VDOM в виде дерева. Каждый элемент является узлом этого дерева. При изменении состояния любого элемента, создается новое дерево. Затем это новое дерево сравнивается (diffed) со старым.

После этого вычисляется наиболее эффективный метод внесения изменений в RDOM. Цель данных вычислений состоит в минимизации количества операций, совершаемых с RDOM. Тем самым, уменьшаются накладные расходы, связанные с обновлением RDOM.

На изображениях ниже представлено виртуальное DOM-дерево и процесс согласования.

Красным цветом обозначены узлы, которые были обновлены. Эти узлы представляют элементы UI, состояние которых изменилось. После этого вычисляется разница между предыдущей и текущей версиями виртуального DOM-дерева. Затем все родительское поддерево подвергается повторному рендерингу для представления обновленного UI. Наконец, это обновленное дерево используется для обновления RDOM.

Как React использует VDOM?

После того, как мы рассмотрели, что такое VDOM, настало время поговорить о том, как он используется в React.

1. React использует паттерн проектирования «Наблюдатель» (observer) и реагирует на изменения состояния

В React каждая часть UI является компонентом и почти каждый компонент имеет состояние (state). При изменении состояния компонента, React обновляет VDOM. После обновления VDOM, React сравнивает его текущую версию с предыдущей. Этот процесс называется «поиском различий» (diffing).

После обнаружения объектов, изменившихся в VDOM, React обновляет соответствующие объекты в RDOM. Это существенно повышает производительность по сравнению с прямыми манипуляциями DOM. Именно это делает React высокопроизводительной библиотекой JavaScript.

2. React использует механизм пакетного (batch) обновления RDOM

Это также положительно влияет на производительность. Названный механизм предполагает отправку обновлений в виде пакетов (набора, серии) вместо отправки отдельного обновления при каждом изменении состояния.

Повторная отрисовка UI — самая затратная часть, React обеспечивает точечную и групповую перерисовку RDOM.

3. React использует эффективный алгоритм поиска различий

React использует эвристический O(n) (линейный) алгоритм, основываясь на двух предположениях:

  1. Два элемента разных типов приводят к построению разных деревьев
  2. Разработчик может обеспечить стабильность элементов между рендерингами посредством пропа key (ключ)

На практике эти предположения являются верными почти во всех случаях.

При сравнении двух деревьев, React начинает с корневых элементов. Дальнейшие операции зависят от типов этих элементов.

Элементы разных типов

  • Если корневые элементы имеют разные типы, React уничтожает старое дерево и строит новое с нуля
  • Вместе со старым деревом уничтожаются все старые узлы DOM. Экземпляры компонента получают componentWillUnmount() . При построении нового дерева, новые узлы DOM встраиваются в DOM. Экземпляры компонента получают сначала UNSAFE_componentWillMount() , затем componentDidMount() . Любое состояние, связанное со старым деревом, утрачивается
  • Любые компоненты, являющиеся дочерними по отношению к корневому, размонтируются, их состояние уничтожается. Например, при сравнении:

Старый Counter будет уничтожен и создан заново.

Элементы одинакового типа

При сравнении двух элементов одинакового типа, React «смотрит» на атрибуты этих элементов. Узлы DOM сохраняются, изменяются только их атрибуты. Например:

После сравнения этих элементов будет обновлен только атрибут className .

После обработки узла DOM, React рекурсивно перебирает всех его потомков.

Рекурсивный перебор дочерних элементов

По умолчанию React перебирает два списка дочерних элементов DOM-узла и генерирует мутацию при обнаружении различий.

Например, при добавлении элемента в конец списка дочерних элементов, преобразование одного дерева в другое работает хорошо:

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

Использование ключей

Для решения данной проблемы React предоставляет атрибут (проп) key . Когда дочерние элементы имеют ключи, React использует их для сравнения потомков текущего и предыдущего узлов. Например, добавление ключей к элементам из последнего примера сделает преобразование деревьев намного более эффективным:

Теперь React знает, что элемент с ключом 0 является новым, а элементы с ключами 1 и 2 старыми.

На практике в качестве ключей, как правило, используются идентификаторы:

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

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

Изменение порядка элементов при использовании индексов в качестве ключей также может привести к проблемам с состоянием элементов. Экземпляры компонента обновляются и повторно используются на основе ключей. Если ключом является индекс, перемещение элемента приведет к изменению ключа. Как результат, состояние компонента для таких вещей, как неуправляемое поле для ввода данных, может смешаться и обновиться неожиданным образом.

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

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

Поскольку «виртуальный DOM» — это в большей степени паттерн, нежели конкретная технология, данное понятие может означать разные вещи. В мире React «виртуальный DOM», обычно, ассоциируется с React-элементами, которые являются объектами, представляющими пользовательский интерфейс. Тем не менее, React также использует внутренние объекты, которые называются «волокнами» (fibers). В этих объектах хранится дополнительная информация о дереве компонентов. Fiber — это новый движок согласования, появившийся в React 16. Его основная цель заключается в обеспечении инкрементального рендеринга VDOM.

Как выглядит VDOM?

Название «виртуальный DOM» делает концепцию немного магической (мистической). На самом деле, VDOM — это обычный JavaScript-объект.

Представим, что у нас имеется такое DOM-дерево:

Это дерево может быть представлено в виде такого объекта:

const vdom = < tagName: 'html', children: [ < tagName: 'head' >, < tagName: 'body', children: [ < tagName: 'ul', attributes: < class: 'list' >, children: [ < tagName: 'li', attributes: < class: 'list_item' >, textContent: 'Элемент списка', >, // конец li ], >, // конец ul ], >, // конец body ], > // конец html 

Это наш VDOM. Как и RDOM, он является объектным представлением HTML-документа (разметки). Однако, поскольку он представляет собой всего лишь объект, мы можем свободно и часто им манипулировать, не прикасаясь к RDOM без крайней необходимости.

Вместо использования одного объекта для всего документа, удобнее разделить его на небольшие секции. Например, мы можем выделить из нашего объекта компонент list , соответствующий неупорядоченному списку:

const list = < tagName: 'ul', attributes: < class: 'list' >, children: [ < tagName: 'li', attributes: < class: 'list_item' >, textContent: 'Элемент списка', >, ], > 

VDOM под капотом

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

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

Первым делом, нам нужна копия VDOM с изменениями, которые мы хотим осуществить. Поскольку нам не нужно использовать DOM API, мы можем просто создать новый объект.

const copy = < tagName: 'ul', attributes: < class: 'list' >, children: [ < tagName: 'li', attributes: < class: 'list_item' >, textContent: 'Первый элемент списка', >, < tagName: 'li', attributes: < class: 'list_item' >, textContent: 'Второй элемент списка', >, ], > 

Данная копия используется для создания «различия» (diff) между оригинальным VDOM ( list ) и его обновленной версией. Diff может выглядеть следующим образом:

const diffs = [ < newNode: < /* новая версия первого элемента списка */ >, oldNode: < /* оригинальная версия первого элемента списка */ >, index: < /* индекс элемента в родительском списке */ >, >, < newNode: < /* второй элемент списка */ >, index: < /* . */ >, >, ] 

Данный diff содержит инструкции по обновлению RDOM. После определения всех различий мы можем отправить их в DOM для выполнения необходимых обновлений.

Например, мы можем перебрать все различия и либо добавить нового потомка, либо обновить существующего в зависимости от различия:

const domElement = document.quesrySelector('list') diffs.forEach((diff) => < const newElement = document.createElement(diff.newNode.tagName) /* Добавляем атрибуты . */ if (diff.oldNode) < // Если имеется старая версия, заменяем ее новой domElement.replaceChild(diff.newNode, diff.oldNode) >else < // Если старая версия отсутствует, создаем новый узел domElement.append(diff.newNode) >>) 

Обратите внимание, что это очень упрощенная версия того, как может работать VDOM.

VDOM и фреймворки

Обычно, мы имеем дело с VDOM при использовании фреймворков.

Копцепция VDOM используется такими фреймворками, как React и Vue для повышения производительности обновления DOM. Например, с помощью React наш компонент list может быть реализован следующим образом:

Для обновления списка достаточно создать новый шаблон и снова передать его ReactDOM.render() :

const newList = React.createElement( 'ul', < className: 'list' >, React.createElement( 'li', < className: 'list_item' >, 'Первый элемент списка' ), React.createElement('li', < className: 'list_item' >, 'Второй элемент списка') ) const timerId = setTimeout(() => < ReactDOM.render(newList, document.body) clearTimeout(timerId) >, 5000) 

Поскольку React использует VDOM, даже несмотря на то, что мы повторно рендерим весь список, обновляются только фактически изменившиеся части.

Заключение

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

Подход, используемый Angular , который является фреймворком, благодаря которому одностраничные приложения (single page applications, SPA) обрели столь широкую известность, называется Dirty Model Checking (грязной проверкой моделей). Следует отметить, что DMC и VDOM не исключают друг друга. MVC-фреймворк вполне может использовать оба подхода. В случае с React это не имеет особого смысла, поскольку React — это, в конце концов, всего лишь библиотека для слоя представления (view).

Облачные VDS от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Отрисовка элементов

Элементы — это самые маленькие строительные блоки приложений React.

Элемент описывает, что вы хотите видеть на экране:

const element = h1>Hello, worldh1>;

Unlike browser DOM elements, React elements are plain objects, and are cheap to create. React DOM takes care of updating the DOM to match the React elements.

В отличие от DOM-элементов браузера, элементы React — обычные объекты, лёгкие для создания. React DOM берёт заботу по обновлению DOM на себя для соответствия элементам React.

Примечание:

Может сбить с толку элементы с более широко известной концепцией «компонентов». Мы представим компоненты в следующем разделе (/docs/components-and-props.html). Элементы — это то, что из чего компоненты «сделаны», и мы рекомендуем вам прочитать этот раздел, прежде чем идти вперёд.

Отрисовка элемента в DOM

Предположим, что в вашем файле HTML есть :

div id="root">div>

Мы называем это «корневым» узлом DOM, потому что всё внутри него будет управляться DOM React.

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

Чтобы отрисовать элемент React в корневом узле DOM, передайте его в ReactDOM.render() :

const element = h1>Привет, мирh1>; ReactDOM.render(element, document.getElementById('root'));

На странице отобразится «Привет, мир».

Обновление отрисованного элемента

React-элементы — неизменяемы. Создав однажды элемент, вы не сможете изменить его дочерние элементы или атрибуты. Элемент похож на один кадр в фильме: он представляет собой пользовательский интерфейс в определённый момент времени.

Насколько известно из предыдущих разделов, единственный способ обновить интерфейс — создать новый элемент и передать его в ReactDOM.render() .

Рассмотрим этот пример тикающих часов:

function tick()  const element = ( div> h1>Привет, мир!h1> h2>Сейчас new Date().toLocaleTimeString()>.h2> div> ); ReactDOM.render(element, document.getElementById('root')); > setInterval(tick, 1000);

Он вызывает каждую секунду ReactDOM.render() из колбэка setInterval() .

Примечание:

На практике большинство приложений React только один раз вызывают ReactDOM.render() . В следующих разделах мы узнаем, как такой код инкапсулируется в [компоненты с состоянием] (/docs/state-and-lifecycle.html).

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

React обновляет только то, что необходимо

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

Вы можете убедиться в том, проверив последний пример с помощью инструментов браузера:

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

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

Как работат метод render в js?

Метод render() используется в библиотеке React для отображения компонента на странице.

Он возвращает React-элемент, который описывает, как должен выглядеть компонент на странице. Для этого он использует JSX-синтаксис — это расширение синтаксиса JavaScript, которое позволяет писать HTML-подобный код внутри JavaScript.

Пример использования метода render() :

import React from 'react'; import ReactDOM from 'react-dom'; class MyComponent extends React.Component  render()  return ( div> h1>Hello, world!/h1> p>This is my first React component./p> /div> ); > > ReactDOM.render(MyComponent />, document.getElementById('root')); 

В этом примере мы создали класс MyComponent , который наследует от класса React.Component . Внутри класса мы определили метод render() , который возвращает React-элемент. Далее мы использовали функцию ReactDOM.render() для отображения компонента на странице.

Когда React запускает метод render() , он сравнивает полученный элемент с предыдущим состоянием и обновляет только те части страницы, которые изменились. Это позволяет достичь высокой производительности и быстрого отображения изменений на странице.

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

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