Это первая статья моего класса по интерпретации исходного кода React.Прежде всего, давайте поговорим о том, почему я написал эту серию статей:
- Сейчас я в основном использую React в своей работе, поэтому хочу понять внутренние принципы
- На рынке существует бесчисленное множество интерпретаций исходного кода Vue, но, напротив, очень мало связанных с React, Это также связано с тем, что исходный код React сложен, поэтому я хочу решить эту проблему.
- Я чувствую, что не обязательно понимаю то, что понимаю, но я действительно понимаю, когда пишу это для понимания читателями, поэтому я хочу писать то, что понимаю.
Ожидается, что эта серия статей превысит десять статей.Реакция версия составляет 16,8,6Вот места, на которые стоит обратить внимание в этой серии:
- Это продвинутый курс. Если он включает в себя контент, в котором вы не разбираетесь, пожалуйста, погуглите его самостоятельно. Кроме того, лучше всего иметь возможность разработки React.
- Это курс по исходному коду, понять его, только читая, невозможно, его нужно дополнить Демо и Отладкой, чтобы по-настоящему понять назначение кода.
- Я разветвляю версию кода 16.8.6 и добавляю подробные китайские комментарии к коду, который я прочитал. Студенты, которые не могут дождаться моей статьи, могут сначала прочитать еемой склад,И, пожалуйста, следуйте вместе с моим комментарием кодом, как вы прочитаете эту серию. Поскольку разные версии могут привести к различным кодам, и я не буду вставлять большую часть кода в статье, я объясню только некоторые коды более подробно, и другие коды могут быть прочитаны с моими комментариями.
- Первая проблема, с которой вы сталкиваетесь при чтении исходного кода, заключается в том, что вы не знаете, с чего начать. Этот комментарий к коду может помочь вам решить эту проблему. Вам просто нужно следовать моему коммиту, чтобы прочитать его.
- Не будет интерпретировать какой-либо код в среде DEV, не будет интерпретировать весь код, будут интерпретировать только основные функции (даже это будет большой проект)
- В последний раз, чтобы упомянуть,Обязательно статьи икодв сочетании, места ради не буду вставлять все коды, надоело копировать, а читатели устали читать
Содержание этой статьи не составит труда, позвольте мне сначала разогреться для вас, пожалуйста, откройте ее.мой кодИ найдите src в папке реакции, которая также является папкой входа React.
Прежде чем входить в текст, расскажу о своих идеях написания в этой серии: 1. Код должен быть максимально отображен через картинки, что и красиво и легко читается.В любом случае не нужно всем копировать код код. 2. В статье будет рассказано только о том коде, который я считаю важным или интересным.Для других кодов, пожалуйста, прочитайте мой репозиторий самостоятельно.В любом случае, код был аннотирован. 3. Вызовы функций с длинными процессами будут представлены в виде блок-схем. 4. Я не буду просто сухо говорить о коде, а расскажу о том, какие проблемы эти API могут нам помочь решить в сочетании с реальной ситуацией.
Информация, связанная со статьей
- Исходный код React 16.8.6 Китайские комментарии, эта ссылка является ядром статьи, конкретный код и количество строк кода в статье основаны на этом репозитории
- Рендер процесс (1)
- процесс визуализации (2)
React.createElement
Каждый должен был написать JSX при написании кода React, но зачем вам импортировать React, если вы используете JSX?
Это связано с тем, что наш код JSX будет скомпилирован Babel какReact.createElement
, вы не сможете использовать его без знакомства с ReactReact.createElement
.
<div id='1'>1</div>
// 上面的 JSX 会被编译成这样
React.createElement("div", {
id: "1"
}, "1")
Тогда мы сначала находимReactElement.jsПрочитать файлcreateElement
Реализация функции
export function createElement(type, config, children) {}
первыйcreateElement
Функция получает три параметра, которые представляют собой то, что, как мне кажется, каждый может понять самостоятельно через вещи, скомпилированные JSX выше.
тогда дляconfig
Немного обработки:
этот код правильныйref
так же какkey
Сделайте проверку (для такого кода вам не нужно читать внутреннюю реализацию, вы можете понять, что она хочет сделать, по имени функции), затем перейдитеconfig
И поместите несколько встроенных свойств (например,ref
а такжеkey
) удаляется и бросается в объект реквизита.
Далее абзац дляchildren
операция
Сначала выньте параметры после второго параметра, а затем оцените, больше ли длина единицы. Если оно больше единицы, значит, их несколько.children
,В этот моментprops.children
Будет массивом, иначе просто объектом.Поэтому мы должны обратить внимание наprops.children
При обходе обращайте внимание на то, является ли это массивом, конечно, вы также можете использоватьReact.Children
API вReact.Children
API в .
Наконец, он возвращаетReactElement
объект
Внутренний код очень прост,основнойчерез?typeof
чтобы помочь нам определить, что этоReactElement
, мы можем увидеть много таких похожих типов позже. Еще одна вещь, на которую нам нужно обратить внимание, это: Написано JSX.<APP />
представляет собойReactElement
,APP
Представляет компонент React.
Ниже представлена блок-схема этого подраздела:
ReactBaseClasses
упомянутый вышеAPP
Представляет компонент React, то в этом разделе мы прочитаем компонент, связанный сReactBaseClasses.jsкод под файлом.
На самом деле, прежде чем читать эту часть исходного кода, я думал, что код будет очень сложным, возможно, включая много логики в компонентах, но внутренний код оказался достаточно простым. Это связано с тем, что команда React поместила всю сложную логику в папку react-dom, вы можете думать о react-dom как о интерфейсе между React и пользовательским интерфейсом.клеевой слой, этот слой клея совместим со многими платформами, такими как Web, RN, SSR и т. д.
Файл содержит два основных компонента, а именноComponent
а такжеPureComponent
, давайте сначала прочитаемComponent
эта часть кода.
КонструкторComponent
Следует отметить два моментаrefs
а такжеupdater
, первое будет специально представлено ниже, последнее является очень важным атрибутом в компоненте, мы можем найтиsetState
а такжеforceUpdate
называютсяupdater
метод, ноupdater
Это контент в react-dom, об этой части мы узнаем в последующих статьях.
Кроме тогоReactNoopUpdateQueue
Также есть отдельный файл, но неважно, читается внутренний код или нет, потому что он используется для сообщения предупреждений.
Далее мы читаемPureComponent
На самом деле код в этой части в основном такой же, как иComponent
последовательный
PureComponent
унаследовано отComponent
, метод наследования использует очень типичную паразитарную композицию.
В дополнение к этим двум частям кода вы можете обнаружить, что каждый компонент имеетisXXXX
Атрибуты используются для определения того, какому компоненту они принадлежат.
Выше приведен код для этой части, мы узнаем в следующем разделе.refs
часть контента.
Refs
На самом деле существует несколько способов создания рефов:
- Строковый метод, но этот метод устарел
ref={el => this.el = el}
React.createRef
В этом разделе мы узнаемReact.createRef
Связанный контент, два других метода не входят в объем этой статьи, пожалуйста, найдитеReactCreateRef.jsдокумент.
Внутренняя реализация проста, если мы хотим использоватьref
, просто выньтеcurrent
объект.
Кроме того, для функциональных компонентов нельзя использоватьref
Да, если вы не знаете причину, вы можете прочитать ее напрямуюДокументация.
Конечно, раньше был хитрый путь, т. е. черезprops
способ передачиref
, но теперь у нас есть новый способforwardRef
Для решения этой проблемы.
См. конкретный кодforwardRef.jsДокумент, тот же внутренний код все еще очень прост
Этот код — самое важное, что мы можем получить в параметрахref
, так что если мы хотим использовать в компоненте функцииref
Вы можете написать такой код:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
))
ReactChildren
Этот раздел будет самой сложной частью этой статьи.Возможно, вам придется написать демо и отладить его самостоятельно, чтобы действительно понять, почему исходный код реализован таким образом.
Во-первых, вам нужно найтиReactChildren.jsфайл, в этой части кода я расскажу только оmapChildren
Содержимое, связанное с функциями, потому что эта часть кода в основном проходит через весь файл.
Если вы не использовали этот API, вы можете прочитать его самостоятельноДокументация.
дляmapChildren
Для этой функции он обычно используется в шаблоне проектирования составных компонентов. Если вы не знаете, что такое составной компонент, вы можете взглянуть на Ant-design, который часто использует этот шаблон проектирования внутри, напримерRadio.Group
,Radio.Button
, а также здесь есть статьиДокументацияЭто вводит шаблон проектирования.
Давайте сначала посмотрим на некоторые волшебные способы использования этой функции.
React.Children.map(this.props.children, c => [[c, c]])
Для приведенного выше кодаmap
то естьmapChildren
Возвращаемое значение функции равно[c, c, c, c]
. Независимо от того, как возвращаемое значение вашей второй функции параметра является вложенным массивом из нескольких измерений,map
Функция может помочь вам сгладить одномерный массив, а количество элементов в возвращаемом массиве после каждого обхода показывает, сколько раз необходимо скопировать один и тот же узел.
Если текстовое описание немного сложно понять, давайте посмотрим на код:
<div>
<span>1</span>
<span>2</span>
</div>
Для приведенного выше кода,c => [[c, c]]
После конвертации становится
<span>1</span>
<span>1</span>
<span>2</span>
<span>2</span>
Далее перейдем к делу, посмотримmapChildren
Как это работает внутри.
Интересная часть этого кода заключается в том, что он вводит концепцию пула повторного использования объектов, соответствующуюgetPooledTraverseContext
а такжеreleaseTraverseContext
код в . Конечно, использование этой концепции на самом деле очень простое.Это поддержка пула повторного использования объектов фиксированного размера.Каждый раз, когда объект берется из этого пула для присвоения значения, свойства объекта становятся пустыми, а затем отбрасываются обратно. в бассейн. Цель поддержания этого пула — повысить производительность, ведь частое создание и удаление объекта со многими свойствами будет потреблять производительность.
Далее мы будем учитьсяtraverseAllChildrenImpl
Код в этой части кода нужно разделить на две части
Эта часть кода относительно проста, основная часть состоит в том, чтобы судитьchildren
Что такое тип . Если это узел, который можно отобразить, вызовите его напрямую.callback
, а также можно обнаружить, что в процессе суждения используется код?typeof
процесс суждения. здесьcallback
ОтноситсяmapSingleChildIntoContext
функция, содержание этой части будет упомянуто ниже.
Эта часть кода будет сначала судитьchildren
Это массив. Если это массив, выполните итерацию по массиву и рекурсивно вызовите каждый элементtraverseAllChildrenImpl
, то есть это должен быть единственный отображаемый узел для выполнения кода в первой половине кода.callback
.
Если это не массив, посмотритеchildren
Можно ли поддерживать итерацию, принцип - пройтиobj[Symbol.iterator]
Способ получения итератора, если возвращаемое значение является функцией, значит она поддерживает итерацию, а дальше логика та же, что и раньше.
законченныйtraverseAllChildrenImpl
функция, мы прочитаем ее в концеmapSingleChildIntoContext
реализация в функции.
bookKeeping
это то, что мы берем из пула объектов, а затем вызываемfunc
И входящий узел (в это время этот узел должен быть единственным узлом), в это времяfunc
представляет собойReact.mapChildren
второй параметр в .
Далее следует процесс оценки типа возвращаемого значения: если это массив, он все еще возвращается к предыдущей логике кода, обратите внимание на то, что здесь передается.func
даc => c
, потому что необходимо убедиться, что окончательный результат сглажен; если это не массив, оцените, является ли возвращаемое значение допустимым элементом, и, если проверка пройдена, клонируйте копию и замените ееkey
и, наконец, поместите возвращаемое значение вresult
середина,result
На самом деле, этоmapChildren
Возвращаемое значение.
Слишком далеко,mapChildren
Содержимое, связанное с функцией, было проанализировано, и учащиеся, которые не очень хорошо разбираются, могут снова просмотреть его с помощью следующей блок-схемы.
остальные
В предыдущих разделах была рассмотрена большая часть интересного кода в папке react, а в остальном остались некоторые закоулки и закоулки. Напримерmemo
,context
,hooks
,lazy
, Эта часть кода может быть прочитана вами непосредственно, если вам интересно.В любом случае, содержание по-прежнему очень простое, а сложная часть находится в папке react-dom.
Список других статей
наконец
Чтение исходного кода — очень утомительный процесс, но и польза от него огромна. Если у вас возникнут какие-либо вопросы в процессе чтения, вы можете связаться со мной в области комментариев, и, конечно же, вы также можете упомянуть Issus в репозитории.
Кроме того, написание этой серии является очень трудоемким проектом. Вам необходимо поддерживать комментарии к коду. Вы должны написать статью как можно больше, чтобы читатели могли ее понять. Наконец, вы должны добавить рисунки. Если вы считаете, что статья выглядит ладно, пожалуйста, не скупитесь на свои.
Следующая статья будет о волокне, и она будет разделена на несколько статей для объяснения.
Наконец, если вы считаете, что контент полезен, вы можете обратить внимание на мой официальный аккаунт «Внешняя часть действительно забавная», вас ждет много хорошего.