Когда мы сможем умело использовать React для фронтенд-разработки, мы неизбежно проявим большой интерес к внутреннему механизму React. Что такое компоненты? Это действительно ДОМ? На чем основано выполнение функции жизненного цикла?
В этой статье давайте сначала изучим реализацию и монтирование компонентов React.
1. Какие компоненты
Начните с написания самого простого компонента:
После написания приведенного выше кода мы получаем<A />
Вот этот компонент, тогда давайте сначала разберемся<A />
что. использоватьconsole.log
Распечатай:
Как можно видеть,<A />
На самом деле это js-объект, а не настоящий DOM, на этот раз обратите вниманиеprops
является пустым объектом. Далее печатаем<A><div>这是A组件</div></A>
, и посмотрите, что выводит консоль:
Мы видели,props
изменился из-за<A />
Компонент вложен вdiv
,div
Текст снова вложен, поэтому в описании<A />
объектprops
добавлено вchildren
свойство, значением которого является описаниеdiv
js-объект. Точно так же, если мы выполняем многоуровневую вложенность компонентов, то фактически они находятся в родительском объекте.props
увеличить вchildren
Поля и соответствующие им значения описания, то есть многоуровневая вложенность js-объектов.
Приведенное выше описание основано на режиме разработки React ES6, фактически переданном в ES5.React.createClass({})
Компоненты, созданные этим методом, точно такие же, как в ES6, и их также можно проверить, распечатав результаты компонентов в консоли, которые здесь повторяться не будут.
Так как же компоненты React выглядят как теги HTML, но на самом деле являются объектами?
Поскольку объявление нашего компонента основано наReact
иComponent
, так что сначала мы открываемReact.js
, вы можете увидеть следующий код:
мы вimport React from 'react'
При импорте объект React предоставляется в исходном коде. существуетextends Component
, унаследовалComponent
своего рода. Здесь необходимо отметить два момента:
- Исходный код явно используется
module.exports
вместоexport default
, почему его можно успешно внедрить? На самом деле это заслуга парсера babel. это делает(ES6)import === (CommonJS)require
. В то время как в машинописном тексте строгийexport default
объявление, поэтому его нельзя использовать в машинописном текстеimport React from 'react'
Теперь заинтересованные читатели могут попробовать его. - мы можем написать
extends Component
также могу написатьextends React.Component
, есть ли разница между ними? ответ отрицательный. так какComponent
даReact.Component
цитаты. то естьComponent === React.Component
, который может быть записан в реальном проекте.
вместеReactComponent
подсказки, которые мы открываемnode_modules/react/lib/ReactComponent.js
:
Приведенный выше код представляет собой знакомый конструктор, и все должны быть с ним знакомы. В то же время мы также заметилиsetState
Это метод, определенный на прототипе с двумя параметрами, конкретный принцип которого будет объяснен в главе, посвященной механизму обновления React.
Приведенный выше код показывает, что компонент A, который мы объявили в начале, на самом деле унаследован.ReactComponent
Подкласс класса, прототип которогоsetState
и другие методы. Таким образом, компонент А уже имеет самый простой прототип.
резюме
2. Инициализация компонентов
После объявления A мы можем настроить методы внутри него или использовать методы жизненного цикла, такие какComponentDidMount
Подождите, это точно так же, как когда мы писали «классы». Единственное отличие состоит в том, что класс компонента должен иметьrender
Вывод метода примерно такой<div>这是A组件</div>
Структура компонента, смонтированная на реальном DOM, может инициировать жизненный цикл компонента и стать частью дерева DOM. Сначала мы наблюдаем, как «классы» ES6 инициализируют реагирующий компонент.
Поместите исходный пример кода в babel:
в_Component
является объектомReactComponent
,_inherit
путьextends
Функциональная реализация ключевых слов, это контент, связанный с ES6, мы пока его проигнорируем. Дело в том, что мы нашлиrender
метод на самом деле называетсяReact.createElement
метод (фактически метод ReactElement). тогда мы открываемReactElement.js
:
Увидев это, мы обнаруживаем, что на самом деле каждый компонентный объект проходит черезReact.createElement
метод созданReactElement
тип объекта. другими словами,ReactElment
— это объект, который внутренне записывает характеристики компонентов и сообщает React, что вы хотите видеть на экране.
существуетReactElement
середина:
параметр | Функции |
---|---|
?typeof |
Идентификационная информация компонента |
key |
Идентификация структуры DOM для повышения производительности обновления |
props |
Информация о подконструкции (добавить, если есть)children поле/ничего не пусто) и свойства компонента (например,style ) |
ref |
Ссылка на настоящий DOM |
_owner |
_owner === ReactCurrentOwner.current (ReactCurrentOwner.js), значением является объект для создания текущего компонента, значение по умолчанию равно null. |
Прочитав вышеприведенный контент, я считаю, что у каждого есть определенное понимание сути компонентов React. выполнивReact.createElement
созданныйReactElement
Тип объекта js — «Компонент React», что точно соответствует результату, выведенному на консоль. Подводя итог, если мы пройдемclass
ключевое слово объявляет компоненты React, затем они анализируются в настоящий DOM, пока не будутReactElement
js объект типа.
резюме
Чтобы дополнить предыдущую интеллект-карту:
3. Монтаж компонентов
Мы знаем, что это можно сделатьReactDOM.render(component,mountNode)
Смонтируйте пользовательский компонент/собственный DOM/строку в виде
Так как же реализован процесс монтажа?
ReactDOM.render
на самом деле вызывает внутреннийReactMount.render
, а затем выполнитьReactMount._renderSubtreeIntoContainer
. Из буквального смысла видно, что это логика вставки "дочернего DOM" в контейнер.Посмотрим на реализацию исходного кода:
Этот код очень важен,render
Все функции функции здесь (нажмите на картинку для увеличения).
Давайте разберем входящие_renderSubtreeIntoContainer
Параметры:
параметр | Функции |
---|---|
parentComponent |
Родительский компонент текущего компонента при первом отображенииnull
|
nextElement |
Компонент для вставки в DOM, напримерhelloWorld
|
container |
контейнер для вставки, напримерdocument.getElementById('root')
|
callback |
Функция обратного вызова после завершения |
Функции этих параметров хорошо понятны, далее проведем логический анализ построчно:
- строка 2: добавить текущий компонент на предыдущий уровень
props
под свойствами. (Вложенные отношения родитель-потомок объясняются в начале этой статьи следующим образом:props
поставка) - строка 4 ~ 22: вызов
getTopLevelWrapperInContainer
метод, чтобы определить, есть ли компонент под текущим контейнером, обозначенный какprevComponent
; если естьprevComponent
заtrue
, выполнить процесс обновления, то есть вызвать_updateRootComponent
метод. Если он не существует, удалите его. (перечислитьunmountComponentAtNode
метод) - Строка 24: обновляется ли он или выгружается, в конечном итоге он будет смонтирован в реальном DOM. посмотри
._renderNewRootComponent
Исходный код:
Проанализируйте процесс:
- появляется строка 3
instantiateReactComponent
Способ упаковки, об этом мы поговорим позже. - в строке 5
batchedMountComponentIntoNode
вызов как транзакцияmountComponentIntoNode
(Транзакция достанет статью для анализа), этот метод возвращает HTML, соответствующий компоненту, который записывается как переменная.markup
. иmountComponentIntoNode
Последний звонок_mountImageIntoNode
, посмотрите исходный код:
Основной код — это последние две строки.setInnerHTML
это метод, который будетmarkup
Установить какcontainer
изinnerHTML
атрибут, который завершает вставку DOM.precacheNode
Метод заключается в сохранении обработанных объектов компонента в кэше для повышения скорости обновления структуры.
Процесс инициализации и монтирования компонента React здесь в основном ясен. существуетReactDOM.render()
При использовании метода мы заметим, что этот метод может монтировать компоненты React, строки или собственный DOM. Теперь мы уже знаем, что на самом деле монтирование заключается в использованииinnerHTML
свойства, но React обрабатывает их по-разному для разных структур элементов?
Как упоминалось выше, на предпоследнем этапе монтажа компонентов, который заключается в выполнении_renderNewRootComponent
метод, мы видим, что существуетinstantiateReactComponent
метод возвращает обработанный объект. ПосмотримinstantiateReactComponent
Исходный код:
входящие параметрыnode
этоReactDOM.render
Компонентный параметр метода, входnode
и выводinstance
Его можно свести в следующую таблицу:
node |
фактические параметры | результат |
---|---|---|
null /false
|
нулевой | СоздайтеReactEmptyComponent компоненты |
object && type === string
|
виртуальный DOM | СоздайтеReactDOMComponent компоненты |
object && type !== string
|
Реагировать компоненты | СоздайтеReactCompositeComponent компоненты |
string |
нить | СоздайтеReactTextComponent компоненты |
number |
номер | СоздайтеReactTextComponent компоненты |
Чтобы разобраться в процессе:
- в соответствии с
ReactDOM.render()
Когда передаются разные параметры, React создаст внутри четыре типа инкапсулированных компонентов, обозначенных какcomponentInstance
. - а затем передать его в качестве параметра
mountComponentIntoNode
В методе получается соответствующий компоненту HTML, который записывается как переменнаяmarkup
. - Преобразование реального свойства DOM
innerHTML
Установить какmarkup
, то есть вставка DOM завершена.
Итак, вопрос в том, как разобрать HTML на втором шаге выше? Ответ заключается в том, что в процессе инкапсуляции в четыре типа компонентов на первом этапе даются инкапсулированные компонентыmountComponet
метод, выполнение этого метода запустит жизненный цикл компонента, тем самым проанализировав HTML.
Конечно, чаще всего мы используем четыре типа компонентов:ReactCompositeComponent
Компоненты, также известные как компоненты React, имеют полный внутренний жизненный цикл, а также являются наиболее важными компонентами React. Подробные типы компонентов и жизненный цикл мы объясним в следующей статье.
4. Резюме
Используйте диаграмму, чтобы разобраться в процессе компонентов React от объявления до инициализации и монтирования: (нажмите, чтобы просмотреть увеличенное изображение)
обзор:
«Анализ исходного кода React (2): типы и жизненные циклы компонентов»
«Анализ исходного кода React (3): подробная транзакция и очередь обновлений»
«Анализ исходного кода React (4): система событий»
Контактный адрес электронной почты: sssyoki@foxmail.com