Учебное пособие по React: с чего начать и как оно сравнивается

Опубликовано: 2022-03-11

Front-end и JavaScript в частности — странный мир. Количество новых вещей, выпускаемых ежедневно, часто высмеивается людьми, которые с ними не работают, и многими теми, кто работает. Тем не менее, время от времени мы немного перегружены новой информацией, библиотеками и обсуждениями, и нам хотелось бы чего-то стабильного, например, убежища для кораблей, где мы могли бы оставаться подольше. В последнее время React кажется послушной гаванью в море динамической эволюции JavaScript.

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

Иллюстрация React как маяка, четко отображающегося над морем кода JavaScript.

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

Состояние React в 2019 году

React — это библиотека представлений, которую мы можем проследить еще в 2011 году, когда ее первый прототип под названием FaxJs появился на ее странице в Facebook. Сама React была представлена ​​Джорданом Уоке (который также является автором упомянутого прототипа) на JSConfUS на 29 мая 2013 г. и был открыт для свободного доступа на GitHub 2 июля 2013 г.

React продолжал набирать популярность в 2014 году, когда начали появляться конференции для расширения сообщества и популяризации React. Однако, с моей точки зрения, 2015 год стал знаковым для React — крупные компании (например, Airbnb и Netflix) начали любить и принимать решения React. Также в том же году появился React Native. Идея React Native не была чем-то абсолютно новым, но за ней было интересно наблюдать, тем более, что она была поддержана Facebook.

Еще одним большим изменением стал Redux, реализация Flux. Это сделало управление состоянием более доступным и простым, что сделало его наиболее успешной реализацией на сегодняшний день.

С тех пор и сейчас стало доступно множество других вещей, включая инструменты React, переписывание основного алгоритма, Fiber, изменение семантического управления версиями и так далее. Перенесемся в сегодняшний день, мы находимся на 16.6.3, вероятно, за несколько недель до того, как станет доступна новая версия с хуками (предполагалось, что это будет 16.7.0, но она уже выпущена из-за некоторых исправлений для React.lazy). React хорошо известен, стабилен и получает хорошие отзывы.

Но что такое реакция?

Что ж, если вы фронтенд-разработчик и еще не слышали об этом, то я должен вас поздравить, так как это настоящий подвиг.

Шутки в сторону, React — это декларативная библиотека представлений на основе компонентов, которая помогает вам создавать пользовательский интерфейс. Это библиотека, а не фреймворк, хотя поначалу многие описывали его как последний.

Очевидно, что если мы собираемся добавить Redux, React Router и т. д., у него появится все необходимое для создания обычного одностраничного приложения, что может быть причиной того, что его иногда ошибочно называют фреймворком, а не библиотекой. . Во всяком случае, можно утверждать, что со всеми компонентами этой среды вместе термин «фреймворк» несколько подходит, но сам по себе React — это просто библиотека.

Давайте остановимся на номенклатуре и сосредоточимся на том, что отличается в React, на том, чего у нас не было до его появления. Прежде всего, когда вы впервые думаете о React, вы думаете о JSX, поскольку это первое, что приходит вам на ум, когда вы смотрите на код. JSX — это расширение синтаксиса JavaScript, несколько напоминающее HTML/XML. Когда дело доходит до React и JSX, у нас есть несколько отличий от HTML, например, класс в React — className , нет tabindex, но есть tabIndex , стиль принимает объекты JavaScript, которые имеют свойства camelCased, и так далее.

Есть некоторые незначительные различия, но каждый должен их быстро понять. Обработка событий осуществляется, например, с помощью атрибутов onChange и onClick , которые можно использовать для присоединения некоторой функции для обработки событий. Кроме того, компоненты впоследствии можно свободно использовать повторно и настраивать с помощью реквизитов, поэтому нет необходимости писать один и тот же код несколько раз.

 import React, { Component } from 'react'; export default class App extends Component { render() { return ( <div>Hello World, {this.props.name}</div> ); } }

Однако на самом деле JSX не является абсолютно необходимым в React. Вы можете писать обычные функции для создания элементов без использования JSX. Тот же код, что и выше, можно использовать, как показано ниже.

 import React, { Component } from 'react'; export default class App extends Component { render() { return React.createElement( 'div', null, 'Hello World, ', this.props.name ); } }

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

На самом деле, у меня есть еще одна причина, по которой я показал фрагмент выше. Часто разработчики не понимают, зачем нам нужно делать следующее:

 import React from 'react';

Фрагмент должен быть понятным. Несмотря на то, что мы извлекаем Component , нам все еще нужен React, потому что Babel транспилирует выше JSX ниже React.createElement . Так что, если мы не импортируем React, у нас это просто не получится. Я упомянул Babel, инструмент, который помогает нам внедрять то, чего еще нет в JavaScript (точнее, в браузерах) или каким-то образом является его расширением (или другими языками, такими как TypeScript, который Babel поддерживает из Babel 7). Благодаря Бабелю:

  • JSX превратится в функции, понятные браузеру.
  • Мы можем использовать новые функции, которых еще нет в браузерах (например, свойства класса).
  • Мы можем добавлять функции, которые есть в новых браузерах, но которых нет в старых, сохраняя при этом поддержку старых браузеров.

Короче говоря, в JavaScript завтра — это сегодня; это, вероятно, то, что потребует отдельной статьи. Стоит отметить, что импорт React также можно обойти некоторыми другими методами (такими как внедрение ProvidePlugin через Webpack и т. д.), но из-за ограниченного места здесь мы избегаем этого и предполагаем, что пользователь будет использовать приложение Create React ( CRA) (подробнее об этом инструменте будет сказано позже).

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

Чем React отличается от Angular и Vue?

Я очень не люблю сравнивать библиотеки, особенно когда нас заставляют сравнивать груши с яблоками (библиотеки против фреймворков и т. д.).

Поэтому я попытаюсь сравнить React с Angular и Vue, используя серию коротких вопросов и ответов, которые не имеют большого отношения к техническим вопросам, вместо того, чтобы говорить что-то вроде «X лучше, чем Y, потому что он использует JSX, а не шаблоны. ” Подобные моменты обычно являются личными предпочтениями, субъективным выбором. Кроме того, скорость, распределение памяти и т. д. очень похожи в React и всех его основных конкурентах (на ум приходят Angular и Vue). По этому поводу есть действительно хороший отчет, но имейте в виду: подавляющее большинство приложений не выглядят как действительно большие таблицы, которые меняют местами строки в таблице размером 10 КБ. Таким образом, эти результаты также являются чистым экспериментом по скорости. В реальном мире вы бы никогда не сделали ничего подобного.

Иллюстрация React, Angular и Vue.js

Итак, давайте рассмотрим некоторые вопросы, касающиеся React и его сравнения с конкурентами:

Я хочу иметь много возможностей для работы. Насколько популярен React?

Что ж, на этот вопрос легко ответить — выберите React. На самом деле, я бы сказал, что у React примерно в 6-10 раз (довольно большой разброс, но есть порталы, где 1:50, а где-то 1:6) больше вакансий, чем у Vue, и в 2-4 раза больше. чем Угловой. Спрос на специалистов по React высок, так почему же Vue так популярен на GitHub (на самом деле у него больше звезд, чем у React), но у него меньше вакансий? Не имею представления.

Мне нужно большое сообщество, множество библиотек, быстрые решения проблем, которые могут возникнуть.

Реагировать. Не смотрите дальше.

Прост ли он в использовании и делает ли он разработку приятной?

Еще раз, согласно отчетам о состоянии JS за 2018 и 2017 годы, и React, и Vue пользуются действительно хорошей репутацией, и большинство разработчиков говорят, что будут использовать их снова. Angular, с другой стороны, имеет тенденцию из года в год посылать все больше и больше людей, говорящих, что они не будут использовать его снова.

Я хочу создать новое одностраничное приложение, но не хочу искать библиотеки.

Это, наверное, единственное место, где я бы сказал, что Angular — лучший выбор.

Никаких крупных корпораций. Я хочу быть максимально независимым, что мне выбрать?

Vue — единственный независимый в нашем большом трио. (Facebook поддерживает React, а Google — Angular.)

Самый простой старт и самая быстрая кривая обучения?

Вью/Реагировать. Здесь я склоняюсь к Vue, но это только мое личное мнение.

Почему? Потому что вам даже не нужно знать JSX (это необязательно) и это в основном просто HTML + CSS + JavaScript.

Учебник по React: начало работы над вашим первым приложением

Учебное пособие по React: снимок экрана с сообщением об успешном создании приложения React

Самый простой способ начать работу с React в настоящее время — это использовать CRA, инструмент командной строки, который создает для вас проект и помогает избежать всех необходимых настроек для Webpack/Babel и многого другого. Вместо этого вы полагаетесь на то, как он настроен по умолчанию и что было включено в него с течением времени. Благодаря этому вам не нужно заботиться о крупных обновлениях некоторых критически важных библиотек.

Конечно, позже вы можете «извлечь» себя и обрабатывать каждый аспект самостоятельно, запустив npm run eject . У этого подхода есть свои сильные стороны, так как вы можете улучшить свое приложение с помощью вещей, которые в противном случае были бы недоступны (например, декораторы), но он также может быть источником головной боли, поскольку требует много дополнительных файлов и намного больше времени.

Итак, самое первое, что нужно сделать, это:

 npx create-react-app {app-name}

Затем npm run start , и вы готовы к работе.

Класс против функциональных компонентов

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

Существует два типа компонентов класса: Component и PureComponent . Единственная разница между ними заключается в том, что PureComponent выполняет поверхностное сравнение свойств и состояния — у него есть свои преимущества в ситуации, когда вы не хотите делать «пустой» рендеринг, когда компонент и его дочерние элементы находятся в одном и том же состоянии. после рендера. Тем не менее, это лишь поверхностное сравнение; если вы хотите реализовать свое собственное сравнение (например, потому что вы передаете сложные реквизиты), просто используйте Component и переопределите shouldComponentUpdate (который по умолчанию возвращает true). Начиная с версии 16.6+, нечто подобное также доступно с функциональными компонентами — благодаря React.memo , который является компонентом более высокого порядка и по умолчанию ведет себя как PureComponent (поверхностное сравнение), но принимает второй аргумент, в который вы можете передать свое собственное сравнение свойств. .

Как правило, если вы можете использовать функциональный компонент (вам не нужны функции класса), используйте его. Вскоре, начиная с 16.7.0, использование компонентов класса будет требоваться только из-за методов жизненного цикла. Я склонен полагать, что функциональные компоненты более прозрачны, о них легче рассуждать и понимать.

Реагировать на методы жизненного цикла

Иллюстрация монтажа, обновления и демонтажа компонентов

Конструктор (реквизит)

  • Необязательно, особенно с учетом популярности CRA, где объявления полей классов для JavaScript включены по умолчанию. Бессмысленно объявлять, если вы связываете свои методы с помощью функции стрелки внутри тела класса. Подобное состояние также может быть инициализировано как свойство класса.
  • Следует использовать только для инициализации локального состояния для объектов и методов привязки в классах ES6.

компонентDidMount()

  • Совершайте вызовы Ajax здесь.
  • Если вам нужны прослушиватели событий, подписки и т. д., добавьте их здесь.
  • Вы можете использовать setState здесь (но это заставит компонент перерисовываться).

компонентWillUnmount()

  • Удаляет все, что все еще выполняется — например, Ajax должен быть прерван, подписка отменена, таймеры очищены и т. д.
  • Не вызывайте setState , так как это бессмысленно, потому что компонент будет размонтирован (и вы получите предупреждение).

componentDidUpdate (prevProps, prevState, моментальный снимок)

  • Происходит, когда компонент только что завершил обновление (не происходит при первоначальном рендеринге).
  • Имеет три необязательных для использования параметра (предыдущие реквизиты, предыдущее состояние и моментальный снимок, который появится только в том случае, если ваш компонент реализует getSnapshotBeforeUpdate ).
  • Происходит только в том случае, если shouldComponentUpdate возвращает значение true.
  • Если вы используете setState здесь, вы должны охранять его, иначе вы попадете в бесконечный цикл.

shouldComponentUpdate(nextProps, nextState)

  • Только для оптимизации производительности.
  • Если он возвращает false, то рендер НЕ будет вызываться.
  • Вместо этого можно использовать PureComponent , если переопределенный SCO представляет собой просто поверхностное сравнение реквизитов/состояний.

получитьSnapshotBeforeUpdate()

  • Может использоваться для хранения некоторой информации о текущем DOM, например, текущей позиции прокрутки, которую впоследствии можно повторно использовать в componentDidUpdate для восстановления позиции прокрутки.

componentDidCatch (ошибка, информация)

  • Место, где должны происходить ошибки регистрации.
  • Может вызывать setState , но в будущих выпусках он будет заменен статическим методом getDerivedStateFromError(error) , который будет обновлять состояние, возвращая значение для обновления состояния.

Есть два дополнительных метода, которые являются статическими и упоминались в других объяснениях.

статический getDerivedStateFromError (ошибка)

  • Информация об ошибках доступна здесь.
  • Должен возвращать значение объекта, которое будет обновлять состояние, которое можно использовать для обработки ошибок (путем отображения чего-либо).
  • Поскольку он статичен, он не имеет доступа к самому экземпляру компонента.

статический getSnapshotBeforeUpdate (реквизит, состояние)

  • Следует использовать в тех случаях, когда свойства меняются со временем — например, согласно документам React, это может быть полезно для компонента перехода.
  • Поскольку он статичен, он не имеет доступа к самому экземпляру компонента.

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

Состояние против реквизита

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

 import React, { Component } from 'react'; export default class App extends Component { render() { return ( <div> <HelloWorld name="Someone :)"/> </div> ); } } const HelloWorld = (props) => <div>Hello {props.name}</div>

В приведенном выше примере name является реквизитом. Реквизиты доступны только для чтения и не могут быть изменены непосредственно в дочерних компонентах. Кроме того, есть одна плохая практика, которую часто используют люди, а именно копирование свойств в состояние и последующая работа с состоянием. Конечно, бывают случаи, когда вы хотите сделать что-то вроде «начальное состояние, которое будет обновлять родительский компонент после отправки», но это более редко — в таком сценарии может иметь смысл передача начального состояния. Кроме того, в дочерние компоненты можно передавать не только такие свойства, как строки, но и числа, объекты, функции и т. д.

В свойствах также есть еще одна полезная вещь, которая называется defaultProps , статическое поле, которое может сообщить вам, какие свойства по умолчанию используются для компонента (например, когда они не передаются компоненту).

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

Состояние , с другой стороны, является локальным состоянием, которое можно изменить, но косвенно, с помощью this.setState . Если кто-то изменит состояние напрямую, компонент не будет знать об изменении и не будет перерисован, чтобы отразить упомянутые изменения в состоянии.

SetState — это метод изменения объекта локального состояния (путем поверхностного слияния), после чего компонент отвечает на это повторной визуализацией. Имейте в виду, что после использования setState свойство this.state не будет сразу отражать изменения, упомянутые в функции (оно имеет асинхронный характер), поскольку несколько экземпляров setState могут быть объединены вместе из-за оптимизации. У него есть несколько способов вызова, где одна из этих возможностей позволяет нам что-то сделать с компонентом сразу после обновления состояния:

  • setState({value: '5'})
  • setState((state, props) => ({value: state.name + “'s”}))
  • setState([object / function like above], () => {}) — эта форма позволяет нам прикрепить callback , который будет вызываться, когда состояние будет отражать данные, которые мы хотели иметь (в первом аргументе).
 import React, { Component } from 'react'; export default class App extends Component { state = { name: 'Someone :)' } onClick = () => this.setState({ name: 'You' }) render() { return ( <div> <HelloWorld name={this.state.name} onClick={this.onClick}/> </div> ); } } const HelloWorld = (props) => <div onClick={props.onClick}>Hello {props.name}</div>

Реагировать на контекст

React недавно стабилизировал Context API (который был в React в течение довольно долгого времени, но был экспериментальной функцией, несмотря на то, что широко использовался некоторыми из самых популярных библиотек, таких как Redux), что помогает нам решить одну проблему: сверление реквизита. Коротко говоря, реквизиты — это способ передачи реквизитов глубоко внутри структуры — например, это может быть какая-то тема для компонентов, локализация для определенного языка, информация о пользователе и т. д. До Context (точнее, до того, как он стал неэкспериментальным) он был детализирован путем рекурсивного прохождения от родителя к дочернему до последнего листа (очевидно, был Redux, который также мог решить проблему). Имейте в виду, что эта функция решает ТОЛЬКО сверление реквизита и не заменяет такие вещи, как Redux или Mobx. Очевидно, что если вы использовали библиотеку управления состоянием только для этого, вы можете свободно заменить ее.

Подведение итогов

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

Связанный: Сохраняйте контроль: руководство по Webpack и React, Pt. 1