Как стать автором
Обновить

Как разобраться в исходном коде React

Время на прочтение 6 мин
Количество просмотров 13K

React самая популярная библиотека для построения пользовательских интерфейсов. Мы знаем про виртуальное дерево, движок fiber, процедуру reconcilation, хуки и другие прекрасные возможности react. Но как это работает на уровне исходного кода? Ответить на этот вопрос смогут очень небольшое количество программистов.

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

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

С чего начать?

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

Помимо документации следует посмотреть доклады, почитать статьи с более детальным описанием как это работает изнутри. Например по react fiber можно найти много докладов и обсуждений как это устроено.

Следующее грядущее крупное изменение в react - concurrent режим, что можно найти по нему?

Доклад Дэна Абрамова на JSConf Iceland 2018, где concurrent режим еще назывался asynchronous (за 3-4 года до реализации возможности):

Несколько скрытых статей в документации React, на которые нет ссылки из меню: https://reactjs.org/docs/concurrent-mode-intro.html (внутри ссылки на остальные статьи)

Когда изучили чего ожидать внутри репозитория, можно переходить к исследованию исходного кода.

Структура репозитория

Открывая папку с исходниками react, мы увидим довольно простую структуру:

Корень репозитория react
Корень репозитория react

fixtures содержат небольшие приложения для отладки различных возможностей react.js

packages - основная директория с исходниками react, содержит более 35 пакетов, в которых хранится весь исходный код, основные из них:

  • react - содержит весь код для создания компонентов

  • react-reconciler - пакет для сравнения виртуальных деревьев react

  • react-dom и react-native-renderer библиотеки для рендера в различных средах, где может работать react

  • react-devtools* - несколько пакетов для отладки react приложений на более высоком уровне, чем просто javascript код

Сборка react

В разделе contribution на сайт reactjs.org можно найти инструкцию как запустить react в режиме разработчика, как на существующем проекте, так и используя фикстуры, хранящиеся в репозитории react:

https://reactjs.org/docs/how-to-contribute.html#development-workflow

Интересно что информация в русской и англоязычных версиях документации отличается:

Отсутствующий раздел в русскоязычной документации react
Отсутствующий раздел в русскоязычной документации react

Воспользуемся следующей командой для сборки:

yarn build react/index,react-dom/index --type=UMD

И откроем файл:

fixtures/packaging/babel-standalone/dev.html

Для поддержки преобразований jsx используется самый простой путь - подключается babel через тэг script:

<html>
  <body>
    <script src="../../../build/node_modules/react/umd/react.development.js"></script>
    <script src="../../../build/node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
    <div id="container"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello World!</h1>,
        document.getElementById('container')
      );
    </script>
  </body>
</html>

Исходный код и отладка

Перейдем непосредственно к отладке и разбору исходного кода.

Первый и вариант, который никогда не стоит забрасывать - хождение по исходному коду. React использует библиотеку для строгой типизации - flow, поэтому из ключевых участков кода можно почерпнуть информацию не только из javascript'а, но в том числе из типов. Также во многих местах содержатся объемные комментарии, описывающие не только текущее место, но и концептуально где это может использоваться и зачем.

Пара слов про flow

Если вы просто разбираетесь как работает react, то глубоких знаний flow не нужно, достаточно просто понимать что за двоеточием тип, а дальше гуглить по ситуации.

Например по конструкции

{| описание типа |}

можно понять что она относится к объектам и найти информацию в разделе документации связанным с этим.

https://flow.org/en/docs/types/objects/

Абзац документации flow про точный объектный тип
Абзац документации flow про точный объектный тип

Если вы хотите принимать активное участие в разработке react, то без использования flow.js не обойтись. К сожалению flow стал довольно закрытым проектом, который использует, в основном, facebook для своих целей, об этом довольно завуалировано написал Vladan Djeric в описании куда движется flow:

https://medium.com/flow-type/clarity-on-flows-direction-and-open-source-engagement-e721a4eb4d8b

По flow.js есть хороший курс на youtube от Ильи Климова, который был заброшен, из-за смены вектора развития библиотеки. Последнее видео - ноябрь 2018, но во flow за более чем 2 года ничего принципиально не поменялось.

Отладка сверху вниз

Собрали реакт, открыли, например, фикстуру fixtures/packaging/babel-standalone/dev.html в браузере, и начинаем отладку.

Отладкой сверху вниз я условно называю нахождение в исходном коде функции render из react-dom, простановки в ней брейкпоинта и идти вниз по функциям, разбираясь шаг за шагом что происходит, при этом не видя всей картины.

Функция render библиотеки react-dom
Функция render библиотеки react-dom

Отладка снизу вверх

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

На вкладке Performance в Chrome нажимаем Start profiling and reload page, ждем пару секунд и останавливаем работу профайлера.

Профайлинг приложения, используещего babel.js через тег script
Профайлинг приложения, используещего babel.js через тег script

Среди кучи вызовов babel'я, видим небольшое дерево работы react.js, начинающееся с функции render.

Находим из интересующего поддерева самую нижнюю функцию, например для commitRoot, в данном случае, это функция insertOrAppendPlacementNodeIntoContainer, нажимаем на нее:

Нижняя функция в работе процедуры commmit библиотеки react
Нижняя функция в работе процедуры commmit библиотеки react

В блоке Summary видим ссылку на функцию, кликаем, попадаем на вкладку Source

Функция из react-dom библиотеки
Функция из react-dom библиотеки

Ставим брейкпоинт где-нибудь внутри, обновляем страницу. Это дает стек вызовов, по которому мы дошли до этого места:

Стек вызовов при комите react приложения
Стек вызовов при комите react приложения

legacy функция связана с тем, что уже написано много кода для react 18, и часть функций становятся устаревшими.

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

Аналогично можно исследовать любые возможности, очевидно что надо для этого сделать: подготовить проект, запустить профайлер, произвести действия на странице, чтобы вызвалось то что хотим исследовать, остановить профайлер, в графе профайлера найти нужные функции и начать исследование.

Например создаем такой код:

<script type="text/babel">
  const App = () => {
    const [count, setCount] = React.useState(0);

    return (
      <div>
        <h1>Count: {count}</h1>
        <button onClick={() => setCount(count + 1)}>Increase</button>
        <button onClick={() => setCount(count - 1)}>Decrease</button>
      </div>
    );
  }

  ReactDOM.render(
    <App />,
    document.getElementById('container')
  );
</script>

Нажимаем Increase с запущеным Performance сбором информации и смотрим что получилось:

Performance при изменении стейта в react компонение
Performance при изменении стейта в react компонение

updateState просто вызывает updateReducer, который, в свою очередь, уже делает всю работу по изменению state. updateReducer не самая хорошая функция, примерно 150 строк, но при этом содержит много комментариев, облегчающих понимание работы.

Зачем вообще это нужно?

Количество пользователей и разработчиков библиотеки react
Количество пользователей и разработчиков библиотеки react

Во первых, конечно, для интереса. Если вам не достаточно просто работать с библиотекой react как пользователь (программист-пользователь, который использует её в своем коде, но не разрабатывает), и интересно как это всё устроено изнутри, то можно войти в небольшое комьюнити разработчиков react.

Можно попытаться использовать такой путь для карьерного роста, из топ 10 react контрибьюторов, по количеству комитов - 8 работают в facebook. Хотя, конечно, комиты бывают разные.

14 комитов за 120 строк и за 4000
14 комитов за 120 строк и за 4000

Можно просто набратся опыта как разрабатываются и развиваются топовые библиотеки - законодатели мод в сфере front-end разработки, но для этого, конечно, надо участвовать в обсуждениях, глубоко вникать в ключевые изменения и активно контрибьютить.

Куда копать дальше и источники информации

Конечно же основной источник информации - документация, после нее идут выступления и статьи основных разработчиков react, обычно это Dan Abramov, но также можно найти выступления и статьи от других контрибьюторов.

Обычно после каких-либо публикаций, энтузиасты разбираются в этих возможностях и делают доклады, например по теме concurrent в react уже можно найти несколько видео на просторах youtube.

Плейлист с анализом исходников react 17 и рисованием диаграмм как это работает от JSer (на английском): https://www.youtube.com/playlist?list=PLvx8w9g4qv_p-OS-XdbB3Ux_6DMXhAJC3

Просто исследовать - скучно

Просто разбираться как что-то работает утомительно, и я советую как можно раньше перейти к активной фазе - написанию кода, для первых комитов специально создан тег в github - good first issue.

Работа над первым изменением позволит ковыряться не просто так, а с гораздо большим интересом.

Надеюсь было полезно и интересно. Спасибо за внимание!

Теги:
Хабы:
+9
Комментарии 2
Комментарии Комментарии 2

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн