image Привет, Хаброжители!

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

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

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

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

Чтобы извлечь максимум пользы из книги, желательно иметь опыт работы с HTML, CSS и JavaScript, но быть экспертом в этих областях не обязательно. Что еще важнее, вам не понадобится знание React — мы начнем с самого начала и дойдем до того момента, когда вы станете уверенно строить сложные приложения!
Структура книги
Книга включает десять глав, посвященных отдельным темам; за ними следуют три главы проектов. Первые десять глав расположены в естественной последовательности. Читателям без опыта работы с React мы рекомендуем знакомиться с ними по порядку, чтобы обучение было наиболее эффективным.

Если у вас уже есть опыт работы с React, вы можете сразу переходить к интересующей вас главе. В главах с 1-й по 4-ю читатель знакомится с React и ее основными концепциями: структурой компонентов, JSX и функциональными компонентами. Если эти темы вам уже знакомы, эти главы можно пропустить.

В главах с 5-й по 7-ю описаны различные хуки, включая базовые хуки состояния (глава 5), хуки эффектов (глава 6) и прочие (глава 7). В главах 8 и 9 рассматриваются события и формы соответственно. Чтобы освоить приемы работы с полями ввода в формах, просто необходимо отлично разбираться в событиях.

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

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

Выполнение эффектов в компонентах


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

Другая возможная идея — установить тайм-аут вызовом setTimeout. В этом случае через 1 секунду после рендеринга компонента мы увеличиваем значение состояния счетчика, что, в свою очередь, станет причиной повторного рендеринга и создания нового тайм-аута. Решение выглядит логично. Но что, если компонент будет отрендерен повторно по другим причинам? Повторный рендеринг компонента может быть инициирован изменением свойства или существованием нескольких значений состояния, которые могут изменяться независимо от счетчика. Если компонент демонтируется, потому что он уже не нужен, тайм-аут продолжит работать, и через секунду будет сделана попытка обновить несуществующий компонент. К сожалению, этот способ тоже не подходит.

Для решения этой проблемы React вводит хук эффектов с именем useEffect (обратите внимание на важный префикс use*, используемый в именах всех хуков). Эффект в хуке useEffect инициируется при изменении любого значения в наборе зависимостей. Более того, при выполнении эффекта в useEffect можно задать функцию очистки, которая будет выполняться в одном из двух случаев: перед повторным срабатыванием эффекта или при демонтировании компонента. На рис. 6.1 показана логика выполнения.



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

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

  • В компоненте загружаются внешние данные. Чтобы правильно реализовать эту возможность в эффекте, он должен выполняться сразу же после монтирования компонента.
  • Создается таймер с использованием интервала. Для этого такой эффект должен выполняться при монтировании компонента и удаляться при демонтировании.
  • Требуется отслеживать момент закрытия диалогового окна независимо от того, как оно было закрыто. Чтобы правильно реализовать эту возможность, такой эффект должен выполняться только при демонтировании компонента.
  • Требуется обновить заголовок окна (или вкладки) браузера названием текущей отображаемой страницы. Чтобы это делалось в эффекте, он должен выполняться при каждом изменении свойства заголовка, но не при изменении любых других свойств, если заголовок остается неизменным.
  • Требуется запустить таймер, но только в том случае, если он активен, что обозначается флагом isActive. Для этого эффект и его очистка должны выполняться при каждом изменении флага isActive, но не при изменении других свойств или значений, если флаг isActive сохраняет прежнее значение.

Выполнение эффекта при монтировании


Предположим, вы создаете компонент раскрывающегося списка, который загружает выводимые данные с внешнего сервера. Загрузка данных должна совершаться как эффект, выполняемый при монтировании, и никогда не должна происходить повторно (потому что данные уже загружены). В таком сценарии актуальна только часть диаграммы, выделенная на рис. 6.2.



Код приведен в листинге 6.1, а результат его выполнения показан на рис. 6.3.


Репозиторий: rq06-remote-dropdown
Этот пример находится в репозитории rq06-remote-dropdown. Вы можете использовать этот репозиторий, создав новое веб-приложение на основе соответствующего шаблона:
$ npx create-react-app rq06-remote-dropdown --template
                       rq06-remote-dropdown
На следующем сайте можно просмотреть код, увидеть работу приложения непосредственно в браузере или загрузить исходный код в виде zip-файла: rq2e.com/rq06-remote-dropdown

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

Выполнение эффекта при монтировании и очистки при демонтировании


Вам поручено создать компонент-секундомер. Он должен сразу же при монтировании запускать интервал, который просто инкрементно увеличивается с течением времени, а если компонент будет демонтирован (например, пользователь его закрыл) — остановить работу. Для этого потребуется эффект, который выполняется при монтировании и запускает функцию очистки при демонтировании. В таком сценарии актуальна только часть диаграммы, выделенная на рис. 6.4.



Код приведен в листинге 6.2. На рис. 6.5 показан компонент в действии.




Репозиторий: rq06-stopwatch
Этот пример находится в репозитории rq06-stopwatch. Вы можете использовать этот репозиторий, создав новое веб-приложение на основе соответствующего шаблона:
$ npx create-react-app rq06-stopwatch --template rq06-stopwatch
На следующем сайте можно просмотреть код, увидеть работу приложения непосредственно в браузере или загрузить исходный код в виде zip-файла: rq2e.com/rq06-stopwatch

И хотя мы используем переменную setSeconds внутри эффекта, она не указывается как зависимость — это стабильная переменная, которая не изменяется. Функция обновления состояния, возвращаемая хуком useState, всегда остается одной и той же функцией по ссылке. Ее можно включить в массив; работа хука не изменится. Если эта часть покажется вам слишком сложной, просто включите функцию в массив.

События


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

Отмена действия при демонтировании


Третий вариант сценария использования для монтирования и демонтирования расширяет пример из предыдущего раздела. Компонент RemoteDropdown загружает данные при монтировании, но что произойдет, если данные передаются недостаточно быстро и пользователь уже вышел из раздела приложения с раскрывающимся списком, не дождавшись ответа? Произойдет попытка обновить состояние компонента, который больше не существует!

Избежать этого можно двумя способами: либо отменить запрос в функции очистки (в JavaScript через AbortController), либо создать локальный флаг, который запоминает, находится ли компонент в процессе монтирования, и обновляет состояние компонента только в том случае, если флаг содержит true. В противном случае компонент просто игнорирует возвращенный ответ.

Отмена запроса с использованием AbortController при демонтировании реализуется примерно так:



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



Такое решение работает для любого типа отложенного обратного вызова, выполняемого в хуке эффекта. Это может быть обрабатываемое обещание (promise), сработавший тайм-аут или что-то подобное. Внутри эффекта локальной переменной присваивается false при демонтировании компонента, а далее остается лишь отменить обратный вызов при срабатывании.

Выполнение очистки при демонтировании


Представьте, что вы работаете над большим приложением с компонентом диалогового окна. В этом компоненте выводятся сигналы для пользователя. Диалоговое окно можно закрыть разными способами: нажатием кнопки x в углу, нажатием Escape на клавиатуре, кнопкой OK в нижней части окна и т. д. Ваша задача — обеспечить вызов аналитической функции при закрытии диалогового окна. Можно вручную добавить маленький фрагмент кода для всех разных способов закрытия диалогового окна, но мы знаем, что вместо этого можно выполнить эффект при демонтировании компонента. В таком сценарии актуальна только часть диаграммы, выделенная на рис. 6.6.

Реализация может быть следующей:


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



Другой пример, в котором — какое совпадение! — также встречается диалоговое окно, — это управление фокусом. Когда вы используете клавиатуру для перехода к кнопке и нажимаете Enter, чтобы открыть диалоговое окно, то при следующем закрытии диалогового окна фокус ввода должен вернуться к той же кнопке, чтобы можно было продолжить переход к другим кнопкам интерфейса. При открытии диалогового окна фокус ввода должен перейти внутрь этого окна, но при его демонтировании он должен вернуться к элементу, которому он принадлежал перед открытием диалогового окна. Это можно сделать при помощи хука useEffect, для которого определена только функция очистки.

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

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

Выполнение эффекта при некоторых рендерингах


Согласитесь, хорошо, если бы заголовок вкладки в браузере автоматически обновлялся, когда пользователь переходит по блогу? Весь сайт блога создан на React, и в нем присутствует компонент, который динамически отображает любой пост в блоге. Заголовок документа изменяется в эффекте, который должен выполняться при каждом изменении заголовка блога и не должен — при изменении любых других свойств. В таком сценарии актуальна только часть диаграммы, выделенная на рис. 6.7. Реализация компонента приведена в листинге 6.3.



Репозиторий: rq06-blog-title
Этот пример находится в репозитории rq06-blog-title. Вы можете использовать этот репозиторий, создав новое веб-приложение на основе соответствующего шаблона:
$ npx create-react-app rq06-blog-title --template rq06-blog-title
На следующем сайте можно просмотреть код, увидеть работу приложения непосредственно в браузере или загрузить исходный код в виде zip-файла: rq2e.com/rq06-blog-title

Это классический пример целей, для которых предназначен хук useEffect, — то есть выполнения побочных эффектов компонента. Заголовок документа невозможно обновить через DOM, поэтому его обновление должно быть побочным эффектом; в таких ситуациях useEffect — лучший выбор.

Обновление на основании свойства


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

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



Возможно, этот сценарий трудно понять, но он вполне типичен для компонентов с контролем ввода.
Репозиторий: rq06-email-input
Этот пример находится в репозитории rq06-email-input. Вы можете использовать этот репозиторий, создав новое веб-приложение на основе соответствующего шаблона:
$ npx create-react-app rq06-email-input --template rq06-email-input
На следующем сайте можно просмотреть код, увидеть работу приложения непосредственно в браузере или загрузить исходный код в виде zip-файла: rq2e.com/rq06-email-input

Об авторах
Мортен Барклунд, независимый разработчик, выступавший в качестве ведущего в разных проектах, в том числе в проекте React с открытым кодом, финансируемом Google. Мортен имеет ученую степень в computer science, полученную в Техническом университете Дании; уже более двух десятков лет он активно участвует в жизни сообщества веб-разработчиков и успел поработать над сотнями проектов.

Азат Мардан — автор таких бестселлеров о JavaScript, React и Node.js, как «React быстро», 1-е изд.; «Practical Node.js»; «Pro Express.js», «Full Stack JavaScript» и «TypeScript Mistakes». Он является приглашенным профессором Технологического университета, ментором стартапов и разработчиком или ведущим разработчиком проектов с опытом работы в стартапах и крупных корпорациях, включая YouTube, Google, Capital One, Indeed и DocuSign. Азат преподавал на многих семинарах и курсах, включая курс по edX, который прослушали более 40 000 студентов по всему миру. Азат — лауреат премии Microsoft MVP (Most Valuable Professional) в области технологий разработки и занял 239-е место по активности участия на GitHub в мире. Он выступал с докладами более чем на 30 международных конференциях, в том числе совместно с такими известными технологическими специалистами, как Дуглас Крокфорд (Douglas Crockford), Джефф Этвуд (Jeff Atwood) (один из создателей Stack Overflow), Джим Ягельски (Jim Jagielski) (создатель Apache), Скотт Хансельман (Scott Hanselman) и Дениз Купер (Danese Cooper).

Более подробно с книгой можно ознакомиться на сайте издательства:

» Оглавление
» Отрывок

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — React

Комментарии (2)


  1. GeniyZ
    04.04.2024 11:51
    +2

    Хочу листинги в книгах с подсветкой синтаксиса


  1. metnitskaya
    04.04.2024 11:51
    +1

    Было полезно прочитать, спасибо автору за перевод