Устройство кодовой базы
В этой главе вы узнаете об устройстве кодовой базы React, используемых соглашениях и реализации.
Если вы хотите внести свой вклад в React, то мы надеемся, что эта глава вам поможет.
Мы считаем, что вам не обязательно следовать этим соглашениям в ваших React-приложениях. Многие из этих соглашений существуют по историческим причинам и могут быть изменены со временем.
Top-Level Folders
После клонирования репозитория React вы увидите папки верхнего уровня:
packages
содержит метаданные (такие какpackage.json
) и исходный код (подпапкаsrc
) для каждого пакета из репозитория React. Большая часть работы с кодом происходит в подпапкахsrc
внутри каждого пакета.fixtures
содержит несколько небольших React-приложений для контрибьютеров.build
содержит скомпилированную версию React. Этого каталога нет в репозитории, но он появится после того, как вы соберёте проект в первый раз.
Документация расположена в отдельном репозитории.
Существуют ещё несколько вспомогательных верхнеуровневых папок. Но вы, вероятно, не столкнётесь с ними при изменении кода.
Тесты
У нас нет отдельной верхнеуровневой папки с юнит тестами. Вместо этого, мы помещаем их в папку __tests__
, расположенную рядом с тестируемыми файлами.
Например, тесты для setInnerHTML.js
расположены в __tests__/setInnerHTML-test.js
.
Предупреждения и инварианты
Предупреждения в React выводятся через console.error
.
if (__DEV__) {
console.error('Что-то не так.');
}
Предупреждения включены только в режиме разработки и полностью вырезаны из продакшена. Если вам необходимо запретить выполнение какого-либо кода, тогда используйте модуль invariant
:
var invariant = require('invariant');
invariant(
2 + 2 === 4,
'Ты не пройдёшь!'
);
Если условие внутри invariant
равно false
, тогда выбрасывается исключение.
«Инварианты» — это всего лишь способ сказать: «Условие всегда истинно». Вы можете думать о них как об утверждениях (assertion).
Важно чтобы режимы разработки и продакшена имели похожее поведение, поэтому исключения выбрасываются в обоих режимах. Сообщения об ошибках в продакшене автоматически заменяются кодами ошибок, для того, чтобы избежать разрастания бандла.
Режимы разработки и продакшена
Вы можете использовать псевдоглобальную переменную __DEV__
, чтобы блок кода присутствовал только в режиме разработки.
На этапе компиляции добавится проверка process.env.NODE_ENV !== 'production'
, определяющая, должен ли данный блок кода присутствовать в сборке CommonJS.
Выражение будет равно true
в неминифицированной сборке, а в минифицированной будет вырезан весь блок вместе с if
.
if (__DEV__) {
// Этот код будет выполнен только в режиме разработки.
}
Flow
Недавно мы представили статический анализатор Flow. Файлы, помеченные аннотацией @flow
в заголовке после лицензии, будут подвергнуты проверке типов.
Мы принимаем пулл реквесты на дополнение аннотаций Flow в уже существующий код. Вот пример кода:
ReactRef.detachRefs = function(
instance: ReactInstance,
element: ReactElement | string | number | null | false,
): void {
// ...
}
Новый код, если это возможно, должен использовать Flow. Вы можете выполнить yarn
flow
, чтобы произвести проверку типов.
Множество пакетов
React является монолитным репозиторием. Он содержит множество отдельных пакетов, чтобы изменения были согласованными, а проблемы решались в одном месте.
Ядро React
Ядро включает в себя весь верхнеуровневый API React
, например:
React.createElement()
React.Component
React.Children
Ядро включает в себя только API необходимый для объявления компонентов. Оно не включает алгоритм согласования или какой-либо платформо-специфический код. Этот код находится в компонентах React DOM и React Native.
Код ядра расположен в папке packages/react
. Он доступен в npm в виде пакета react
. Соответствующая сборка для браузера экспортирует глобальную переменную React
и называется react.js
.
Рендереры
Изначально React создавался для DOM, но позже был адаптирован к другим платформам, таким как React Native. В этом разделе мы расскажем об используемых рендерерах.
Рендереры превращают React-дерево в платформо-специфический код.
Они расположены в каталоге packages/
:
- React DOM Renderer рендерит React-компоненты в DOM. Он реализует
ReactDOM
API и доступен как пакетreact-dom
из npm репозитория. Можно подключать как отдельный бандлreact-dom.js
, экспортирующий глобальную переменнуюReactDOM
. - React Native Renderer рендерит React-компоненты в нативные представления. Используется внутри React Native.
- React Test Renderer рендерит React-компоненты в JSON-дерево. Используется при тестировании снимками через фреймворк Jest и доступен как пакет react-test-renderer в npm.
Мы начали поддерживать единственный неофициальный рендерер react-art
, который раньше находился в отдельном GitHub-репозитории.
Примечание:
Технически
react-native-renderer
— это очень тонкий слой, который учит React взаимодействовать с React Native. Платформо-специфический код, управляющий нативными представлениями, расположен в репозитории React Native вместе с его компонентами.
Согласователи
Даже очень непохожим рендерерам, таким как React DOM и React Native, необходимо разделять много логики. В частности, реализации алгоритма согласования должны быть настолько похожими, чтобы декларативный рендеринг, пользовательские компоненты, состояние, методы жизненного цикла и рефы работали одинаково между различными платформами.
В качестве решения, различные рендереры имеют между собой общий код. В React мы называем эту часть «согласователь». Когда запланировано такое обновление, как setState()
, согласователь вызывает render()
в дереве компонентов и монтирует, обновляет либо размонтирует их.
Согласователи не являются отдельнымы пакетами, потому что не имеют открытого API. Вместо этого они используются исключительно такими рендерерами как React DOM и React Native.
Согласователь Stack
Согласователь «Stack» — это реализация, которая использовалась в React 15 и более ранних версиях. Мы перестали его использовать, но задокументировали в следующией главе.
Согласователь Fiber
В согласователе «Fiber» мы пытаемся исправить давно существующие ошибки и решить проблемы, появившиеся в согласователе Stack.
Его основными целями являются:
- Разделение прерываемых задач на подзадачи.
- Дать задачам приоритеты, иметь возможность перемещать их и переиспользовать.
- Иметь возможность перемещаться вперёд и назад между родителями и детьми в разметке React.
- Иметь возможность возвращать множество элементов из метода
render()
. - Улучшенная обработка ошибок.
Вы можете узнать больше об архитектуре React Fiber здесь и здесь. Несмотря на то, что он включён в React 16, асинхронная функциональность по умолчанию не включена.
Исходный код расположен в папке packages/react-reconciler
.
Система событий
Для большей кроссбраузерной совместимости в React реализован слой, инкапсулирующий работу с нативными событиями. Его исходный код расположен в каталоге packages/react-dom/src/events
.
Что дальше?
В следующей главе вы познакомитесь с реализацией согласователя (версий React 15 и ранее) более подробно. Для нового согласователя мы ещё не писали документацию.