Разбираем исходный код React: сначала разогреемся

внешний интерфейс React.js

Это первая статья моего класса по интерпретации исходного кода React.Прежде всего, давайте поговорим о том, почему я написал эту серию статей:

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

Ожидается, что эта серия статей превысит десять статей.Реакция версия составляет 16,8,6Вот места, на которые стоит обратить внимание в этой серии:

  • Это продвинутый курс. Если он включает в себя контент, в котором вы не разбираетесь, пожалуйста, погуглите его самостоятельно. Кроме того, лучше всего иметь возможность разработки React.
  • Это курс по исходному коду, понять его, только читая, невозможно, его нужно дополнить Демо и Отладкой, чтобы по-настоящему понять назначение кода.
  • Я разветвляю версию кода 16.8.6 и добавляю подробные китайские комментарии к коду, который я прочитал. Студенты, которые не могут дождаться моей статьи, могут сначала прочитать еемой склад,И, пожалуйста, следуйте вместе с моим комментарием кодом, как вы прочитаете эту серию. Поскольку разные версии могут привести к различным кодам, и я не буду вставлять большую часть кода в статье, я объясню только некоторые коды более подробно, и другие коды могут быть прочитаны с моими комментариями.
  • Первая проблема, с которой вы сталкиваетесь при чтении исходного кода, заключается в том, что вы не знаете, с чего начать. Этот комментарий к коду может помочь вам решить эту проблему. Вам просто нужно следовать моему коммиту, чтобы прочитать его.
  • Не будет интерпретировать какой-либо код в среде DEV, не будет интерпретировать весь код, будут интерпретировать только основные функции (даже это будет большой проект)
  • В последний раз, чтобы упомянуть,Обязательно статьи икодв сочетании, места ради не буду вставлять все коды, надоело копировать, а читатели устали читать

Содержание этой статьи не составит труда, позвольте мне сначала разогреться для вас, пожалуйста, откройте ее.мой кодИ найдите src в папке реакции, которая также является папкой входа React.

Прежде чем входить в текст, расскажу о своих идеях написания в этой серии: 1. Код должен быть максимально отображен через картинки, что и красиво и легко читается.В любом случае не нужно всем копировать код код. 2. В статье будет рассказано только о том коде, который я считаю важным или интересным.Для других кодов, пожалуйста, прочитайте мой репозиторий самостоятельно.В любом случае, код был аннотирован. 3. Вызовы функций с длинными процессами будут представлены в виде блок-схем. 4. Я не буду просто сухо говорить о коде, а расскажу о том, какие проблемы эти API могут нам помочь решить в сочетании с реальной ситуацией.

Информация, связанная со статьей

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.ChildrenAPI вReact.ChildrenAPI в .

Наконец, он возвращает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 в репозитории.

Кроме того, написание этой серии является очень трудоемким проектом. Вам необходимо поддерживать комментарии к коду. Вы должны написать статью как можно больше, чтобы читатели могли ее понять. Наконец, вы должны добавить рисунки. Если вы считаете, что статья выглядит ладно, пожалуйста, не скупитесь на свои.

Следующая статья будет о волокне, и она будет разделена на несколько статей для объяснения.

Наконец, если вы считаете, что контент полезен, вы можете обратить внимание на мой официальный аккаунт «Внешняя часть действительно забавная», вас ждет много хорошего.