Это вторая статья моего анализа исходного кода React, если вы не читали предыдущую статью, обязательно прочтите ее первой.первая статьяНекоторые меры предосторожности, упомянутые в разделе, могут помочь вам лучше читать исходный код.
Информация, связанная со статьей
- Исходный код React 16.8.6 Китайские комментарии, эта ссылка является ядром статьи, конкретный код и количество строк кода в статье основаны на этом репозитории
- Разогрев
- процесс визуализации (2)
пожалуйста, откройте сейчасмой кодИ найдите файл ReactDOM.js в src в папке react-dom. Сегодняшний контент начнется здесь.
render
Предположительно все писали подобный код при написании проектов React.
ReactDOM.render(<APP />, document.getElementById('root')
Этот код сообщает приложению React, что мы хотим отобразить компонент в контейнере, который обычно является кодом входа приложения React.render
Процесс, и будет разделен на несколько статей, чтобы объяснить, потому что процесс слишком длинный.
Прежде всего, найдите строку 702 файла ReactDOM.js, чтобы начать сегодняшнее путешествие.
Эта часть кода на самом деле нечего сказать, только предостережениеlegacyRenderSubtreeIntoContainer
Четвертый параметр прописан мертвым в функцииforceHydrate
дляfalse
. Этот параметрtrue
Это указывает на то, что это рендеринг на стороне сервера, потому что мы анализируем рендеринг на стороне клиента, поэтому содержание этой части не будет расширяться в дальнейшем.
Введите следующийlegacyRenderSubtreeIntoContainer
В функции эта часть кода разделена на две части. первая часть нетroot
Прежде чем нам сначала нужно создатьroot
(соответствует этой статье), вторая часть состоит в том, что естьroot
Процесс рендеринга после этого (соответствует следующей статье).
Когда вы впервые вошли в функцию, не должно бытьroot
, поэтому нам нужно создатьroot
, вы можете найти этоroot
Объект также смонтирован вcontainer._reactRootContainer
, который является нашим DOM-контейнером.
Если у вас есть проект React, вы можете увидеть это, набрав в консоли следующий кодroot
объект.
document.querySelector('#root')._reactRootContainer
каждый может видетьroot
даReactRoot
Построенный конструктором, и есть_internalRoot
объект, которому посвящена данная статьяfiber
Объект, давайте посмотрим на него дальше.
Прежде всего, как было сказано вышеforceHydrate
Контент, связанный с атрибутами, в любом случае вам не нужно беспокоиться об этой части.shouldHydrate
для уверенностиfalse
.
Следующий шаг — удалить все узлы внутри контейнера, вообще говоря, мы пишем такой контейнер
<div id='root'></div>
Эта форма определенно не требует удаления дочерних узлов, что также показывает, что контейнер не должен содержать никаких дочерних узлов. Во-первых, он точно будет удален, а во-вторых, будут выполняться DOM-операции, которые также могут включать перерисовку, перекомпоновку и так далее.
Наконец, создайтеReactRoot
объект и возврат. В дальнейшем мы увидим несколькоroot
, он может быть немного круглым.
существуетReactRoot
Один шаг выполняется внутри конструктора, который заключается в созданииFiberRoot
объект и монтируется на_internalRoot
начальство.Как дерево DOM,fiber
Он также построит древовидную структуру (каждый узел DOM должен соответствоватьfiber
объект),FiberRoot
это всеfiber
корневой узел дерева, мы узнаем оfiber
связанный контент. Здесь упоминается,fiber
Волокно и оптоволокно — это две разные вещи: первое представляет собой структуру данных, а второе — новую архитектуру.
существуетcreateFiberRoot
Внутри функции создаются два соответственноroot
,Одинroot
называетсяFiberRoot
,еще одинroot
называетсяRootFiber
, и оба они ссылаются друг на друга.
Эти два объекта имеют внутри десятки свойств.Сейчас нам не нужно понимать, для чего они используются.На данный момент нам нужно понять только несколько свойств.О других свойствах мы узнаем в следующих статьях.Полезность.
дляFiberRoot
В терминах объектов нам нужно понять только два свойства, которыеcontainerInfo
а такжеcurrent
.前者代表着容器信息,也就是我们的document.querySelector('#root')
; последнее указывает наRootFiber
.
дляRootFiber
Объект, свойства, которые мы должны понимать, немного больше
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
this.stateNode = null;
this.return = null;
this.child = null;
this.sibling = null;
this.effectTag = NoEffect;
this.alternate = null;
}
stateNode
Это было упомянуто выше и не будет повторяться здесь.
return
,child
,sibling
Эти три свойства важны, ониfiber
Основная структура данных дерева.fiber
Дерево на самом деле представляет собой древовидную структуру односвязного списка.return
а такжеchild
Соответствует родительскому и дочернему узлам дерева соответственно, и имеется только один родительский узелchild
Указывает на своего первого дочернего элемента, даже если у родителя есть несколько дочерних элементов. Так как же связаны несколько дочерних узлов? ответsibling
, каждый дочерний узел имеетsibling
Атрибут указывает на следующий дочерний узел, каждый из которых имеетreturn
Атрибут указывает на родительский узел. Это может немного сбивать с толку, давайте разберемся с этим по картинке.fiber
структура дерева.
const APP = () => (
<div>
<span></span>
<span></span>
</div>
)
ReactDom.render(<APP/>, document.querySelector('#root'))
Если нам нужно отрендерить вышеуказанные компоненты, то их соответствующиеfiber
Дерево должно выглядеть так
Как видно из рисунка, каждому компоненту или узлу DOM соответствуетfiber
объект. Кроме того, если у вас есть проект React, вы также можете ввести следующий код в консоли для просмотраfiber
Вся структура дерева.
// 对应着 FiberRoot
const fiber = document.querySelector('#root')._reactRootContainer._internalRoot
Хотя два других атрибута в этой статье не используются, автор считает их очень интересными при просмотре исходного кода, поэтому я планирую их вытащить.
говорящийeffectTag
Прежде давайте разберемся, что такоеeffect
Короче говоря, некоторые операции на DOM, такие как дополнения, делеции и изменения, затемeffectTag
Это для записи всех эффектов, но эта запись реализована побитовой операцией,здесьдаeffectTag
связанный бинарный контент.
Если мы хотим добавитьeffect
Если да, то можете написатьeffectTag |= Update
; если мы хотим удалитьeffect
Если да, то можете написатьeffectTag &= ~Update
.
Ну наконец тоalternate
Атрибуты. На самом деле в приложении React обычно есть дваfiebr
Trees, одно называется старым деревом, а другое называется деревом workInProgress. Первый соответствует отрендерившемуся DOM-дереву, а второй — обновляемому дереву волокон, а также удобен для восстановления после прерывания. Узлы двух деревьев ссылаются друг на друга, что удобно для совместного использования некоторых внутренних атрибутов и уменьшения накладных расходов памяти. В конце концов, я сказал, что каждый компонент или DOM будет соответствоватьfiber
предмет, состоящий из больших словfiber
Дерево также будет очень большим.Если создать два дерева с одинаковыми атрибутами, будет потеряно много памяти и производительности.
Когда обновление завершится, дерево workInProgress заменит старое дерево.Эта практика называется двойной буферизацией, которая также является практикой оптимизации производительности.Заинтересованные студенты могут найти информацию самостоятельно.
Суммировать
Вышеизложенное представляет собой полное содержание этой статьи и, наконец, обобщает содержание этой статьи с помощью блок-схемы.
наконец
Чтение исходного кода — очень утомительный процесс, но и польза от него огромна. Если у вас возникнут какие-либо вопросы в процессе чтения, вы можете связаться со мной в области комментариев.
Кроме того, написание этой серии является очень трудоемким проектом. Вам необходимо поддерживать комментарии к коду. Вы должны написать статью как можно больше, чтобы читатели могли ее понять. Наконец, вы должны добавить рисунки. Если вы считаете, что статья выглядит ладно, пожалуйста, не скупитесь на свои.
Следующая статья связана с процессом рендеринга.
Наконец, если вы считаете, что контент полезен, вы можете обратить внимание на мой официальный аккаунт «Внешняя часть действительно забавная», вас ждет много хорошего.