Анимированное руководство по базовым механизмам React

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



Запуск React-приложения


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

React, при первом запуске приложения, автоматически монтирует класс App к корневому контейнеру приложения.


Первое монтирование <App/>

Virtual DOM и алгоритм сравнения


В ходе работы подсистемы React, реализующей алгоритм сравнения (Diffing Algorithm), выполняется поиск различий между двумя виртуальными DOM (Virtual Document Object Model, виртуальная объектная модель документа). Притормозим ненадолго. Две виртуальные DOM? Вроде бы виртуальная DOM в React только одна… Разберёмся с этим. React выполняет сравнение предыдущей виртуальной DOM с новой. Обновление браузерной DOM производится только в том случае, если при сравнении виртуальных DOM выявлены различия между ними.


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

Рассмотрим то, что происходит на вышеприведённой анимации.

  • По событию click выполняется вызов API.tweet() с данными POST-запроса, содержащими message.
  • В ответ на запрос возвращается payload, эти данные поступают в коллбэк (event) => { … }.
  • Если данные, возвращённые в payload, должны вызывать изменение props — выполняется сравнение деревьев виртуальных DOM.
  • Если деревья оказываются различными — в браузер отправляется самое свежее дерево.
  • Затем новая виртуальная DOM становится старой, а мы ожидаем новых событий.

Компоненты React


Компонент React — это всего лишь JavaScript-объект. React создаёт собственную виртуальную DOM, которая является древовидным представлением всей структуры пользовательского интерфейса. React хранит дерево виртуальной DOM в памяти. Прежде чем то, что находится в виртуальной DOM, окажется физически выведенным в окне браузера, React может выполнить с виртуальной DOM множество операций по добавлению, обновлению и удалению элементов.

Не используйте метод компонентов render() для чего-либо, не имеющего отношению к рендерингу элементов пользовательского интерфейса. Если вам нужно изменить состояние или свойства компонента — используйте стандартные методы жизненного цикла React-компонентов.

Метод render() всегда должен оставаться чистой функцией


Метод render() обновляет виртуальную DOM компонентов. Если новое дерево виртуальной DOM отличается от ранее выведенного дерева, то React, помимо обновления виртуальной DOM, обновит и реальную DOM браузера. Разработчик не должен самостоятельно выполнять непосредственное обновление браузерной DOM. Это правило относится к любым местам в коде React-приложения. Особенно оно важно в применении к функции render().


Не загрязняйте метод render() вызовами функций, которые каким-то образом обновляют DOM напрямую

В методе render() не следует изменять состояние компонента (даже с использованием setState), выполнять HTTP-запросы. Не обращайтесь из этого метода к jQuery, не выполняйте запросы на загрузку неких данных. Дело в том, что метод render() нужно поддерживать в таком состоянии, в котором он представлял бы собой чистую функцию. Этот метод всегда вызывается на заключительном этапе работы механизмов компонента. В ходе его выполнения нужно лишь произвести обновление пользовательского интерфейса. При этом предполагается, что все обновления виртуальной DOM уже выполнены.

События жизненного цикла компонентов


Когда компонент впервые монтируется в DOM, React вызывает событие его жизненного цикла componentWillMount. После того, как виртуальный компонент в первый раз выводится на экран (то есть — впервые монтируется в реальную DOM браузера), вызывается ещё одно событие — componentDidMount.

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

Итоги


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

Уважаемые читатели! Пользуетесь ли вы хуками React?
RUVDS.com
895,22
RUVDS – хостинг VDS/VPS серверов
Поделиться публикацией

Комментарии 21

    0
    В методе render() не следует изменять состояние компонента (даже с использованием setState), выполнять HTTP-запросы. Не обращайтесь из этого метода к jQuery, не выполняйте запросы на загрузку неких данных.


    Кто-то использует React с jQuery???
      0
      Как минимум, при постепенной миграции с jQuery на React они вполне могут какое-то (потенциально неограниченное) время сосуществовать.
        +1
        Я. И очень много людей сидящих на плагинах с jquery за основу.
        +2
        Пока составлялось это руководство, componentWillUpdate() и componentWillMount() успели уйти в UNSAFE :{
          0
          Пока составлялось это руководство классовые компоненты с жизненным циклом по-тихоньку уходят в «UNSAFE» с ноября прошлого года
            +2
            Думаю, для HOC, аггрегирующих большое количество других компонент в себе, чтобы не утонуть в useState/useEffect/useCallback полотнах, все же будут использоваться компоненты с их жизненными циклами
              +1

              Я бы не согласился. Теперь стало наоборот проще в рамках функционального компонента с хуками избавиться от спагетти-кода и изолировать независимый код друг от друга в одном компоненте.

              +1

              Говорить, что они уходят в UNSAFE неправильно, ибо их не депрекейтили и пока даже не планируют.

                0
                github.com/facebook/react/blob/master/CHANGELOG.md#1690-august-8-2019
                они уже deprecated и будут убраны в 17 версии
                  0

                  Задепрекейчены только componentWill{Mount,ReceiveProps,Update}, классы никуда не уходят.

                    0
                    Только сейчас доехал о смысле поста, на который отвечал. Конечно, классы никуда не уходят и не уйдут в ближайшее время)
            +2
            Метод render() всегда должен оставаться чистой функцией

            Судя по отсутствию аргументов эта функция должна всегда давать один и тот же результат, независимо от стейта.

              0

              Я вот недавно рассказывал людям, что «теплый ламповый» реакт с классами и методами — это как геоцентрическая вселенная Птолемея с эпициклами, а хуки — это как гелиоцентрическая система Коперника. Известно, что если взять предел по всем эпициклам Птолемея, то результат получится точно таким же, как у Коперника (и совпадет с наблюдаемым миром). Но только коперниковская система неизмеримо проще и логичнее.


              Точно так же и с хуками: магическим образом от трети до половины кода просто исчезает при рефакторинге с классов на хуки. Это какой-то очень фундаментальный закон мироздания был открыт.


              Так что нет тут никакого «используете ли вы хуки». Есть «весь ли код вы уже перевели на хуки, или пока еще в процессе».

                –1

                А сколько кода исчезнет при переходе с React на $mol...

                  0

                  Сколько?

                    –1

                    Половина так точно.
                    https://github.com/eigenmethod/todomvc/blob/master/examples/react/js — 10KB
                    https://github.com/eigenmethod/todomvc/blob/master/examples/mol — 5.5KB


                    Ну вот взять в пример использование глупого компонента:


                    <TodoItem
                        key={todo.id}
                        todo={todo}
                        editing={this.state.editing === todo.id}
                        onToggle={this.toggle.bind(this, todo)}
                        onDestroy={this.destroy.bind(this, todo)}
                        onEdit={this.edit.bind(this, todo)}
                        onSave={this.save.bind(this, todo)}
                        onCancel={this.cancel}
                    />

                    Аналог на $mol:


                    Item!id $my_todo_row
                        todo?val <=> todo!id?val
                        editing?val <=> todo_editing!id?val

                    Ну или, что то же самое:


                    @ $mol_mem
                    Item( id : string ) {
                        return $my_todo_row.make({
                            todo : val => this.todo( id , val ) ,
                            editing : val => this.todo_editing( id , val ) ,
                        })
                    })
                      0

                      Не знаком глубоко с $mol, но выглядит так, будто в react версии есть всякие onSave, onCancel, в $mol версии такого не вижу

                        0

                        Потому что они для реализации той же функциональности не нужны.


                        Вместо onSave этот компонент дёргает this.todo({ completed , title }), а вместо onCancelthis.editing( false ).


                        Благодаря двусторонним каналам API компонента получается гораздо проще, без 100500 колбэков для управления им.

                          0
                          С таким же успехом можно запихнуть все данные и callback'и в один объект и передать в react компонент и сократить все до:
                          <TodoItem todo={todoGodObject} />
                          Ваш пример на самом_лучшем_фреймворке ничем не лучше такого подхода.
                            0

                            От того, что вы часть кода переложите из одного места в другое, его меньше не станет. Скорее даже наоборот.

                  0

                  С одной стороны я с вами соглашусь — на хуках код писать удобнее и проще. Но кидаться переписывать рабочий код я бы не стал — мало ли что там пойдёт не так. Работает — и пусть работает.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое