Пособие по React всестороннее изучение React.js


Оглавление (нажмите, чтобы открыть):

Скринкаст по React.js

React.js — одна из самых популярных библиотек для создания сложных Frontend-приложений.

Однако, успешная разработка на нём требует хорошего понимания концепций, на которых он построен.

В этом скринкасте мы:

  • Познакомимся с основными понятиями и внутренним устройством React.js.
  • Разберёмся с тем, как создавать компоненты на React.js.
  • Разберём ряд подводных камней, на которые часто наступают начинающие React-разработчики.

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

Они не являются частью собственно React.js, а представляют собой архитектурные надстройки и также постоянно развиваются. Мы осваиваем их на Основном и Продвинутом онлайн-курсах по React.JS.

Автор этого скринкаста – Роман Якобчук, с небольшой помощью в плане организации материала от Ильи Кантора.

Вы также можете скачать все скринкасты в виде архива с видео-файлами.

Учебник по фреймворку React

Учебник по React

  • Урок №
    Учебник по React
    для новичков по-русски
  • Урок №
    Работа с JSX
    в фреймворке React
  • Урок №
    Работа
    с состояниями и событиями
  • Урок №
    Работа
    с if и циклами
  • Урок №
    Продвинутая
    работа с циклами
  • Урок №
    Работа
    с формами
  • Урок №
    Продвинутая
    работа с формами
  • Урок №
    Практика
    по работе с формами
  • Урок №
    Работа
    с компонентами
  • Урок №
    Продвинутая
    работа с компонентами
  • Урок №
    Практика
    по фреймворку React
  • Тут будут еще уроки
    появятся в августе-сентябре.

React является одним из самых популярных JavaScript фреймворков. Фреймворк представляет собой заготовку, которая помогает вам писать код.

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

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

Фреймворки типа React используются для так называемых SPA (single page application — одностраничное приложение). Одностраничное приложение — это сайт, все действия в котором происходят на одной странице, без ее полного обновления.

Примером SPA может служить социальная сеть, работа с почтой и так далее.

Перед изучением React

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

Введение в React

Перед чтением также советую посмотреть вебинар по React, который является введением в этот фреймворк. Вебинар вы найдете по следующим ссылкам: 1, 2, 3, 4, 5, 6, 7, 8.

Подключение React

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

Самым популярным транспойлером является Babel. Им мы и будем пользоваться.

На самом деле реальные проекты на React требуют некоторого знания nodejs и npm. Мы пока не будем с этим заморачиваться, потому что мне хотелось бы, чтобы вы сразу начали писать код.

Для самого простого запуска React нужно подключить такую кучку скриптов:

На продакшене (так называют рабочий сайт) так делать не стоит (так как здесь компиляция кода из новой версии в старую происходит в браузере, а это очень медленно). Мы так делаем для простоты — чтобы вы сразу начали писать код. Попозже мы разберем более сложный способ.

После подключения этих скриптов мы можем выполнять наш ES6 код в теге script с типом text/babel (это важно: не text/javascript, как мы привыкли):

React.js для продолжающих

Итак, вы изучили основы React.js и теперь не знаете, что делать дальше? В статье рассмотрены 5 интересных вещей, которые поднимут ваши навыки и знания React.js на новый уровень.

Жизненный цикл компонента

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

Однако жизненные этапы компонентов немного отличаются от наших. Вот как они выглядят:

Каждый раскрашенный горизонтальный прямоугольник отражает метод жизненного цикла (за исключением «React обновляет DOM и ссылки»). Столбцы отражают разные этапы жизни компонента.

Компонент может находиться только на одном этапе. Всё начинается с монтирования и продолжается обновлением. Компонент постоянно обновляется, пока не будет удалён из виртуального DOM. Затем компонент переходит на этап размонтирования и удаляется из DOM.

12–13 ноября, Санкт-Петербург, беcплатно

Методы жизненного цикла позволяют запускать код в определённые моменты жизни компонента или в ответ на какие-то изменения в ней.

Пройдёмся по каждому этапу жизни компонента и связанным методам.

Монтирование

Так как компоненты на основе классов являются классами (отсюда и название), первый запускаемый метод — это constructor() . Как правило, в constructor() мы инициализируем состояние компонента.

Затем компонент запускает getDerivedStateFromProps() . Опустим этот метод, так как он не очень полезный.

После этого наступает очередь метода render() , который возвращает JSX. Теперь React «монтируется» в DOM.

Наконец, запускается метод componentDidMount() . Здесь выполняются все асинхронные вызовы к базам данных или напрямую управляется DOM. Компонент рождён.

Обновление

Этот этап запускается при каждом изменении состояния или свойств. Как и при монтировании, вызывается метод getDerivedStateFromProps() , но в этот раз без constructor() .

Затем запускается shouldComponentUpdate() . Здесь можно сравнивать старые свойства или состояния с новым набором свойств или состояний. Можно указать, нужно ли заново отображать компонент, вернув true или false . Это позволит сделать приложение более эффективным за счёт уменьшения количества лишних отображений. Если shouldComponentUpdate() возвращает false , на этом этап обновлений завершается.

В противном случае React заново отобразится, а затем запускается getSnapshotBeforeUpdate() . Этот метод тоже не очень полезен. Далее React запускает componentDidUpdate() . Как и componentDidMount() , его можно использовать для асинхронных вызовов или управления DOM.

Размонтирование

Компонент прожил хорошую жизнь, однако всё хорошее рано или поздно кончается. Размонтирование — последний этап жизни компонента. При удалении компонента из DOM React запускает componentWillUnmount() прямо перед удалением. Этот метод используется для закрытия всех открытых соединений вроде веб-сокетов или тайм-аутов.

Другие методы жизненного цикла

Прежде чем мы перейдём к другой теме, давайте вскользь упомянем forceUpdate() и getDerivedStateFromError() .

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

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

Следующий фрагмент кода с CodePen показывает этапы стадии монтирования:

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

Компоненты высшего порядка

Возможно, вы уже использовали компоненты высшего порядка (КВП). Например, функция Redux connection() возвращает КВП. Но что из себя представляют эти компоненты?

Из документации React:

Компонент высшего порядка — это функция, которая принимает компонент и возвращает новый компонент.

Возвращаясь к функции connect() , посмотрим на следующий фрагмент кода:

При вызове connect() мы получаем КВП, который можно использовать для того, чтобы обернуть компонент. Затем мы просто передаём наш компонент в КВП и начинаем использовать возвращаемый им компонент.

КВП позволяют нам абстрагировать общую для компонентов логику в один главный компонент.

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

Вот как всё это может выглядеть без КВП:

Тонна повторяющегося кода и запутанная логика!

И вот как код преобразится с использованием КВП:

Вот CodePen со всем кодом.

Глядя на этот код можно понять, что компоненты могут оставаться очень простыми, даже, если будут производить аутентификацию. Компонент AuthWrapper содержит всю логику аутентификации. Всё, что он делает, — смотрит на свойство isLoggedIn и возвращает WrappedComponent или тег

в зависимости от присвоенного свойству значения.

Как видите, КВП очень полезны, так как позволяют повторно использовать код. Скоро мы к ним вернёмся.

Состояние и setState()

Большинство из вас скорее всего уже использовали состояния React, они были даже в примере с КВП. Однако важно понимать, что при смене состояния React запустит процесс повторного отображения компонента (если не указать иное в shouldComponentUpdate() ).

Поговорим о том, как можно изменить состояние. Единственный способ сделать это — использовать метод setState() . Он принимает объект и объединяет его с текущим состоянием. Помимо этого есть ещё несколько вещей, которые следует знать.

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

Взглянув на эту картинку можно увидеть, что мы сначала вызываем setState() , а затем console.log() . Новое значение переменной counter должно быть равно 1, однако выводится 0. Что если мы хотим получить доступ к новому состоянию после того, как setState() действительно обновит состояние?

Тут мы плавно переходим к следующей вещи, которую нужно знать о setState() — этот метод может принимать callback-функцию. Исправим наш код:

Отлично, всё работает, на этом можно закончить, да? Не совсем. На самом деле, в данном случае мы не используем setState() корректно. Вместо передачи объекта мы передадим методу функцию. Так обычно делается, когда для установки нового состояния используется текущее. Если это не ваш случай, то смело продолжайте передавать объект в setState() . Исправим код ещё раз:

Вот CodePen для этого примера.

В чём смысл передачи функции вместо объекта? Поскольку setState() асинхронный, полагаться на него при создании нового значения немного рискованно. Например, к моменту запуска одного setState() другой setState() мог уже обновить состояние. Передача функции в setState() даёт два преимущества:

  1. Это позволяет создавать статичную копию состояния, которое никогда не изменится само по себе.
  2. Это поместит вызовы setState() в очередь, поэтому они будут запускаться по порядку.

Посмотрим на следующий пример, в котором попытаемся увеличить счётчик на 2, используя два последовательных вызова setState() :

Сравните с кодом ниже:

На первом изображении обе функции setState() напрямую используют this.state.counter , который, как мы узнали ранее, останется со значением 0 после вызова первого setState() . Таким образом, конечное значение равно 1, а не 2, так обе функции setState() устанавливают значение счётчика равным 1.

На втором изображении мы передаём в setState() функцию, что гарантирует последовательный запуск обеих функций. Кроме этого, мы делаем снимок состояния, а не используем текущее, не обновлённое состояние. Теперь мы получили ожидаемый результат.

Вот и всё, что вам нужно знать о состояниях React.

Контекст

Контекст React — это глобальное состояние для компонентов.

API контекста React даёт возможность создавать глобальные объекты компонентов, которые будут доступны любому компоненту. Это позволяет обмениваться данными без необходимости передавать свойства по всему дереву DOM.

Как использовать контекст?

Сначала создадим объект контекста:

В документации React установка контекста в компоненте выглядит так:

Однако в CodePen (React 16.4.2) это не сработало. Вместо этого мы воспользуемся КВП, чтобы использовать контекст образом, похожим на тот, что рекомендует Дэн Абрамов.

Здесь мы оборачиваем компонент в компонент Context.Consumer и передаём в контекст в качестве свойства.

Теперь мы можем написать что-то такое:

И у нас будет доступ к foo из объекта контекста в свойствах.


А как сменить контекст? Это уже немного сложнее, однако мы можем ещё раз использовать КВП и получить что-то такое:

Сначала мы берём исходное состояние контекста — объект, переданный в React.createContext() — и используем его в качестве состояния компонента-обёртки. Затем мы определяем все методы, которые будем использовать для смены состояния. Наконец, оборачиваем наш компонент в компонент Context.Provider . Мы передаём состояние и функцию в свойство value . Теперь они будут в контексте у всех наследников, обёрнутых в компонент Context.Consumer .

Собираем всё воедино (КВП опущены для краткости):

Теперь у дочернего компонента есть доступ к глобальному контексту. У него есть возможность изменить значение атрибута foo в состоянии на baz .

CodePen со всем кодом по теме контекста.

Не пропускайте новостей React!

React активно развивается. Например, в React 16.3 некоторые методы жизненного цикла были упразднены, в React 16.6 появились асинхронные компоненты, а в React 16.7 появились хуки, цель которых — полностью заменить компоненты на основе классов. Следите за развитем React и растите вместе с ним!

Страница поста от канала Библиотека программиста

Обращаем внимание, что мы не несем ответственности за содержимое(content) того или иного канала размещенный на нашем сайте так как не мы являемся авторами этой информации и на сайте она размещается в автоматическом режиме

Пожаловаться

Обращаем внимание, что мы не несем ответственности за содержимое(content) того или иного канала размещенный на нашем сайте так как не мы являемся авторами этой информации и на сайте она размещается в автоматическом режиме

Подробное руководство по React.js в 2020 году

Эта статья была впервые опубликована в 2015 году, на данный момент она дополнена под версию React 16.3 и ее особенности.

Компоненты (Components) — «строительные блоки» в React. Если исходить из контекста Angular, у компонентов много общего с Directives. Если вы используете другой контекст, то это, по существу, виджеты или модули.

Вы можете думать о компонентах как о коллекции HTML, CSS, JS и некоторых «внутренних данных», специфичных для этого компонента. Мне нравится сравнение компонентов с Kolaches в веб. В них есть все, что нужно, запакованное в восхитительный компонуемый сверток.

Компоненты определяются на «чистом» (pure) JavaScript или они могут быть определены на том, что команда React называет “JSX”. Если вы решите использовать JSX (который, вы, вероятнее всего, будете использовать, и это стандартно — мы также будем его использовать для нашего туториала), вам понадобится какой-то этап компиляции, чтобы преобразовать JSX в JavaScript. Но об этом мы поговорим позже.

Что делает React настолько удобным для создания пользовательских интерфейсов (UI), так это то, что данные могут быть получены либо из родительского компонента, либо содержатся в самом компоненте. Прежде чем перейти к коду, давайте удостоверимся, что у нас есть понимание уровня компонентов на уровне высшего порядка.

Выше представлено изображение моего профиля Twitter. Если мы собираемся воссоздать эту страницу на React, мы разделили бы различные секции на разные компоненты (они выделены). Обратите внимание, что компоненты могут иметь вложенные компоненты внутри себя.

Мы могли бы назвать компонент слева (розовый) UserInfo . Внутри UserInfo компонента у нас есть еще один компонент (оранжевый), который мы могли бы назвать UserImages -компонентом.

Мастер Йода рекомендует:  Презентация для программистов Apple WWDC 2020 что нас ждет и где смотреть на русском

Путь, по которому «работают» эти родительско-дочерние отношения — это наш UserInfo -компонент, или родительский компонент, в котором «живет» «состояние» (“state”) данных для него самого (UserInfo), так и для дочернего компонента UserImages .

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

В этом примере мы передаем UserImages-компоненту все изображения, которые есть у пользователя (которые в настоящее время «живут» в UserInfo -компоненте).

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

Эта иерархия parent / child делает управление нашими данными достаточно простым, потому что мы точно знаем, где находятся наши данные и мы не должны манипулировать ими в другом месте.

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

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

На этом этапе вы должны понимать на «очень высоком уровне», как работает React. Теперь давайте перейдем к коду.

Создание первого компонента (JSX, Virtual DOM, render, ReactDOM.render)

Продолжим и напишем наш первый компонент на React.

Чтобы создать компонент на React, будем использовать ES6-класс. Если вы не знакомы с Классами, вы можете продолжить чтение, или узнать о них больше из других источников. (например, здесь — прим.переводчика)

Обратите внимание, что единственный метод в нашем классе — это render . Он является обязательным.

Причина — визуализация (render), описывающая пользовательский интерфейс (UI) нашего компонента. Таким образом, в этом примере текст, который будет отображаться на экране, где «рендерится» этот компонент, — Hello World!

Теперь изучим, что делает ReactDOM.

ReactDOM.render принимает два аргумента. Первый — компонент, который нужно отобразить, а второй — DOM-узел, где необходимо отобразить компонент.

Обратите внимание, мы используем ReactDOM.render , а не React.render . Это изменение в версии React.14, оно произведено, чтобы сделать React более «модульным». Это важно, если вы предполагаете, что React может отображать больше, чем просто DOM-элемент.

В примере выше мы просим React взять наш компонент HelloWorld и выполнить его render в элементе с ID root .

Из-за родительских / дочерних отношений React, о которых мы говорили ранее, обычно использовать ReactDOM.render потребуется только единожды, потому что рендер «самого» родительского компонента уже предполагает отображение всех его вложенных дочерних компонентов.

Теперь на этой стадии вы можете почувствовать немного странное «бросание» «HTML» в свой JavaScript. С тех пор, как вы начали изучать веб-разработку, вам сказали, что вы должны оставить свою логику вне представления, то есть сохранить ваш JavaScript, не связанный с вашим HTML.

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

«HTML», который вы пишете в методе render, на самом деле не HTML, это то, что в React называется «JSX». JSX просто позволяет нам писать HTML-подобный синтаксис, который в конечном итоге преобразуется в легковесные объекты JavaScript. После чего уже React может принимать эти объекты JavaScript и от них формировать «виртуальный DOM» или представление JavaScript реального DOM («виртуальный DOM» — «легковесная копия реального DOM» — прим. переводчика). Это создает ситуацию с выигрышем, когда вы получаете доступность шаблонов с мощью JavaScript.

В примере ниже то, во что в итоге будет скомпилирован ваш JSX.

Теперь вы можете отказаться от фазы преобразования JSX -> JS и написать свои компоненты на React, например, как в коде выше. Но, как вы можете себе представить, это было бы довольно сложно. Я не знаю никого, кто не использует JSX. Для получения дополнительной информации о компиляции JSX посмотрите статьи на тему React Elements vs React Components.

До этого момента мы не выделяли особо важность этой новой виртуальной парадигмы DOM, в которую мы «запрыгиваем».

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

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

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

Процесс выглядит примерно так:

Некоторое пользовательское событие, которое изменяет состояние вашего приложения → ре-рендер виртуального DOM → Различие копий предыдущего виртуального DOM с новым → Обновление только реального DOM и только с необходимыми изменениями.

Поскольку это процесс преобразования от JSX к JS, необходимо настроить какую-то фазу трансформации во время разработки.

Во второй части я расскажу о Webpack и Babel для этого преобразования.

Давайте посмотрим на наш чек-лист «Самых важных частей React» и разберемся, где мы сейчас:

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

Добавление состояния к компоненту (state)

Далее по списку state . Ранее мы говорили о том, как сложно управлять UI, потому что они обычно имеют множество разных состояний. Это случай, когда React действительно начинает «светиться».

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

Возвращаясь к примеру Twitter, UserInfo -компонент, (выделенный розовым цветом), отвечает за управление состоянием (или данными) информации пользователя.

Если другому компоненту тоже нужно это состояние / данные, но это состояние не было прямым дочерним UserInfo , тогда вы создали бы другой компонент, который был бы прямым родителем UserInfo и другого компонента (или обоих компонентов, которым требуется это состояние). Затем вы «прокинете» состояние вниз в качестве props в дочерние компоненты. Другими словами, у вас есть мульти-компонентная иерархия, где общий родительский компонент должен управлять состоянием и передавать его дочерним компонентам через props.

Рассмотрим примерный компонент, который использует свой state:

В этом примере мы использовали новый синтаксис. Первое, что вы заметите, — это метод конструктора. Из определения выше, метод конструктора — «способ установки состояния компонента» (начального состояния — прим.переводчика). Другими словами, любые данные, которые вы помещаете в this.state внутри конструктора, будут частью состояния этого компонента.

В коде выше мы сообщим нашему компоненту, что хотим, чтобы он отслеживал username . Этот username может быть теперь использован внутри нашего компонента через , что является именно тем, что мы делаем в нашем render-методе.

Последнее о чем можно поговорить про state в том, что нашему компоненту нужна возможность изменять собственное внутреннее состояние. Мы делаем это с помощью метода, который называется setState. Помните ранее, когда мы говорили о ре-рендеринге виртуального DOM при каждом изменении данных?

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

Этот «сигнал об уведомлении нашего приложения о том, что некоторые данные изменились» на самом деле просто setState. Всякий раз, когда вызывается setState, виртуальный DOM повторно ре-рендерится, выполняется алгоритм «разницы», а реальный DOM обновляется с необходимыми изменениями.

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

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

Заметьте, мы добавили еще несколько вещей. Во-первых, это handleChange -коллбек. Этот метод будет вызываться каждый раз, когда пользователь что-то вводит в инпут.

Когда вызывается handleChange , он будет вызывать setState , чтобы изменить наш username на значение, которое было введено в поле ввода (e.target.value) (предпочтительнее использовать e.currentTarget.value — прим.переводчика).

Помните, всякий раз, когда вызывается setState , React создает новый виртуальный DOM, выполняет «diff», а затем обновляет реальный DOM.

Теперь давайте посмотрим на наш render-метод. Мы добавили новую строку, содержащую поле ввода. Тип поля ввода, очевидно, будет text . Значение будет значением нашего username (имя пользователя), которое изначально было определено в конструкторе и будет обновлено в методе handleChange .

Обратите внимание, что есть новый атрибут, с которым вы, возможно, разньше не сталкивались — это onChange .

Атрибут onChange является «вещью из React», и он будет вызывать любой метод, который вы указываете, каждый раз, когда изменяется значение в поле ввода — в этом случае указанным нами методом был handleChange . (по аналогии с onchange в нативном javascript — прим.переводчика)

Процесс для кода выше будет выглядеть примерно так:

Пользователь вводит информацию в поле ввода (текст инпут) → вызывается handleChange → состояние нашего компонента меняется на новое значение → React повторно отображается виртуальную DOM → React считывает изменения → реальный DOM обновляется.

Позже, когда мы рассмотрим props, мы увидим несколько более сложных вариантов использования состояния.

А пока, мы идем дальше! Если вы не можете объяснить то, что выделено «галочкой», прочитайте этот раздел еще раз.

Один совет по ДЕЙСТВИТЕЛЬНОМУ изучению React: не позволяйте себе пассивно читать, давая себе ложное чувство понимания материала (почему только React? Это работает везде — прим.переводчика).

Перейдите в песочницу CodeSandbox и попробуйте воссоздать примеры выше (или сделайте свои компоненты), не подглядывая в туториал. Это единственный способ начать обучение React. Это касается и этого урока, и следующего.

Получение state от родительского компонента (props, propTypes, getDefaultProps)

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

Это позволяет архитектуре React оставаться довольно простой. Управляйте state в высшем родительском компоненте, который нуждается в использовании специфических данных и, если у него есть потомок, которому также необходимы эти данные, «прокиньте» данные в качестве props-аргументов.

Вот очень простой пример использования props.

Обратите внимание, что в строке 9 мы имеем параметр name со значением «Tyler». Теперь в нашем компоненте мы можем использовать , чтобы получить «Tyler».

Давайте рассмотрим более продвинутый пример. Теперь у нас будет два компонента. Один — родитель, другой — потомок. Родитель должен отслеживать состояние и передавать часть этого состояния дальше до ребенка в качестве props.

Разберем родительский компонент.

В этом компоненте не так много нового. У нас есть изначальное состояние (initial state, задано в конструкторе) и мы передаем его часть другому компоненту.

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

Помните, что код, который возвращает метод render — это представление того, как должен выглядеть реальный DOM. Если вы не знакомы с Array.prototype.map, этот код может показаться вам немного странным. Все, что делает метод .map — создает новый массив, вызывает коллбек для каждого элемента массива и заполняет новый массив результатом вызова функции-коллбека для каждого элемента.

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

Что примечательно касательно .map, этот метод отлично вписывается в React (и идет «из коробки» в JavaScript). Таким образом, в нашем дочернем компоненте выше мы просто обернули имена в тэг
и сохраняем результат в переменной listItems.

Затем метод render возвращает неупорядоченный список ( ) со всеми нашими друзьями.

Рассмотрим еще пример, прежде чем закончим с props. Важно понимать, что везде, где есть данные, ими можно там же манипулировать. Это упрощает рассуждение о данных. Все методы getter / setter для определенной части данных всегда будут в том же компоненте, где были определены эти данные. Если вам нужно манипулировать какой-то частью данных вне того, где «живут» данные, вы передадите метод getter / setter в этот компонент в качестве props. Давайте посмотрим на такой пример.

Обратите внимание, что в нашем методе addFriend мы добавили новый способ вызова setState. Вместо того, чтобы передавать объект, мы передаем ему функцию, которая затем передается state. Всякий раз, когда вы устанавливаете новое состояние своего компонента на основе предыдущего, (как мы это делаем с нашим массивом друзей), вы хотите передать setState функцию, которая принимает текущее состояние и возвращает данные для слияния с новым состоянием.

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

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

Однако, поскольку мы придерживаемся правила манипулировать данными только из компонента, «которому не все равно», мы передали метод addFriend в наш компонент AddFriend в качестве props и мы вызываем его с new friend после вызова handleAddNew.

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

Прежде чем мы пойдем дальше, хочу рассказать об еще двух возможностях React в отношении props. Это propTypes и defaultProps. Здесь я не буду вдаваться в подробности, потому что они довольно просты.

prop-types позволяют контролировать наличие или типы определенных props, переданных дочернему компоненту. С помощью propTypes вы можете указать, что требуются определенные props или что props являются определенным типом.

Начиная с React.15, PropTypes больше не включается в пакет React. Вам нужно будет установить их отдельно, запустив npm install prop-types .

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

Я изменил наши компоненты и теперь, используя propTypes, мы ожидаем что свойство addFriend будет функцией и что оно (свойство) будет передано в компонент AddFriend. Также, используя defaultProps, мы указали, что если массив друзей не передается компоненту ShowList, он будет пустым по умолчанию.

Итак, мы на последнем участке первой части.

Давайте посмотрим, что у нас осталось по плану.

Мы близки к финалу!

Жизненный цикл компонента (Component LifeCycle)

У каждого компонента, который вы создаете, будут свои события жизненного цикла, которые могут быть полезны для разных манипуляций. Например, если мы хотим сделать запрос AJAX для первого рендера и получить (fetch) данные, в каком lifecycle-методе это лучше сделать? Или, если бы мы захотели запустить какую-то логику, когда props изменились, как мы это сделаем?

Различные события жизненного цикла — ответы на оба вопроса.


Рассмотрим их ниже.

componentDidMount — вызывается один раз после первого рендера. К этому моменту компонент уже есть в DOM. Если вам нужно обратиться к виртуальному DOM — к вашим услугам this.getDOMNode(). Так же это лучший метод жизненного цикла компонента для работы с запросами на сервер.

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

getDerivedStateFromProps — иногда вам нужно обновить состояние вашего компонента на основе «пришедших» props. Это метод жизненного цикла, в котором это можно сделать. Он будет принимать props и state, а возвращаемый объект будет объединен с текущим состоянием.

Мастер Йода рекомендует:  Путь веб-разработчика в 2020

Если вы дошли до этого момента, это отличная работа! Я надеюсь, что это руководство было полезно для вас и теперь вы лучше понимаете React.

Для получения более подробной информации обратитесь к курсу Tyler McGinis React Fundamentals.

Учебник: Введение в React

Учебник не предполагает каких-либо предварительных знаний о React.

Прежде чем мы начнем изучение

  • Начальная настройка проекта – расскажем о том как создать проект.
  • Обзор – расскажем о базовых концепциях React: компоненты (components), свойства (props), и состояния (state).
  • Создание игры – расскажем о наиболее общих техниках разработки на React.
  • Добавление функционала Time Travel (Перемещение по времени) – расскажем более подробно о преимуществах использования React.

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

Что же мы будем создавать?

В этом уроке будет показано, как создать интерактивную игру в крестики-нолики на React.

Вы можете сразу увидеть, окончательный результат здесь. Если на данном этапе код вам совершенно не понятен, не беспокойтесь! Цель этого руководства – помочь вам научится использовать React и его синтаксис.

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

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

Начальная настройка проекта

Мы предполагаем, что вы хотя бы немного знакомы с HTML и JavaScript. Мы также предполагаем, что вы знакомы с такими понятиями программирования, как функции, объекты, массивы и классы.

Если вам нужно почитать о JavaScript, мы рекомендуем прочитать это руководство. Обратите внимание, что мы также используем некоторые функции ES6 – недавней версии JavaScript.

Есть два способа следовать этому руководству: вы можете либо писать код в своем браузере, либо локально создать проект.

Опция 1: Код в браузере

Это самый быстрый способ начать!

Сначала откройте этот стартовый код в новой вкладке. Новая вкладка должна отображать пустую игровую доску в крестики-нолики и код React.

Если вы выбрали этот вариант то вы можете пропустить второй вариант установки и сразу перейти к следующему разделу “Обзор”.

Опция 2: Создание локального проекта

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

  1. Убедитесь что у вас установлена последняя версия Node.js.
  2. Установите через npm Rect командой: npm install -g create-react-app

Далее создайте новый проект:

  1. В папке нового проекта удалите все файлы в папке src/

Примечание: не удаляйте саму папку src , только файлы внутри нее.

  1. Добавьте новый файл index.css с папку src/ со следующим кодом CSS.
  2. Добавьте файл index.js в src/ с этим JS кодом.
  3. Добавьте следующие три линии кода сверху файла index.js в папке src/ :

Сейчас если вы запустите npm start в папке проекта и откроете в браузере https://localhost:3000 , вы должны увидеть пустое поле игры крестики нолики.

Начальный обзор React

Теперь, когда все настроено, давайте рассмотрим что такое React!

Что такое React?

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

В React есть несколько типов компонентов, мы начнем с подкласса React.Component :

Компоненты в React являются строительными кирпичиками из чего строится проект. В примере выше ShoppingList – это класс компонента React. Компонент принимает параметры, называемые props (сокращение от «properties»), и возвращает иерархию представлений, отображаемых с помощью метода рендеринга render.

Метод render возвращает описание того, что вы хотите видеть на экране. React берет описание и отображает результат. В частности, render возвращает React element, который представляет собой упрощенное описание того, что нужно визуализировать. Большинство разработчиков React используют специальный синтаксис под названием «JSX», который облегчает написание этих структур. Так тег

Если вам интересно, createElement() более подробно описан в API reference, но в этом руководстве мы не будем подробно это описывать. Вместо этого мы просто продолжим использование JSX.

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

Компонент из примера выше ShoppingList сейчас рендерит только встроенные компоненты DOM, такие как

Проверка начального кода

Если вы собираетесь работать над учебником в своем браузере, откройте этот код в новой вкладке: Начальный код. Если вы собираетесь работать над учебником с локальным проектом откройте в вашем редакторе файл src/index.js в папке вашего проекта.

Этот стартовый код является основой того, что мы строим. И он уже содержит стили CSS, так что вам нужно сосредоточиться только на изучении React и программировании игры в крестики-нолики.

Изучив код, вы заметите, что у нас есть три компонента React:

Компонент Square отображает одну кнопку , а Board отображает 9 squares (квадратов). Компонент Game отображает игровую доску, которые мы изменим позже. В настоящее время в нашем коде нет интерактивных компонентов.

Передача параметров через props

Просто чтобы попробовать, давайте попытаемся передать некоторые данные из нашего компонента Board в наш компонент Square.

В методе renderSquare в Board измените код, чтобы передать значение с именем prop в Square:

В методе renderSquare компонента Board, измените код, чтобы передать через prop значение value в Square:

Теперь изменим метод render компонента Square что бы отобразить переменную value на :

До наших изменений:

После: Вы должны увидеть номера в каждой клетке поля.

Поздравляем! Вы только что передали “prop” из родительского компонента Board в дочерний компонент Square. Передача prop – это то, как информация передается в приложениях React от родительских к дочерним компонентам.

Делам компонент интерактивным

Давайте добавим немного функциональности. Сделаем так чтобы при клике на компонент Square в нем отображалось “X”. Сначала измените тег кнопки, который возвращается из функции render () компонента Square, следующим образом:

Если вы сейчас кликните по компоненту Square, вы увидите сообщение alert.

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

Обратите внимание на onClick= <() =>alert(‘click’)> , мы передали функции onClick другую функцию. Она запустится только после клика на компонент. Если забудете о () => и напишете onClick= то функцию запуститься сразу после отображения компонента.

На следующем шаге сделаем что бы компонент Square “запоминал” что по нему был клик, и отображал значение “X”. Чтобы компонент мог что нибудь “запомнить”, нужно использовать такое понятие как state.

React компоненты могут использовать state через переменную this.state в их конструкторах. this.state должно рассматриваться как приватная часть компонента React. Давайте сохраним текущее значение value компонента Square в this.state , и изменим это значение при клике по компоненту.

Для этого добавит конструктор в класс компонента:

В классах JavaScript, вам всегда нужно вызывать метод super при определение конструктора подкласса. Поэтому все конструкторы классов React компонентов должны начинаться с вызова super(props) .

Сейчас изменим метод render компонента Square что бы отобразить текущее значение value при клике:

  • Заменим this.props.value на this.state.value внутри тега .
  • Заменим обработчик событий () => alert() на () => this.setState() .
  • Перенесем className и onClick на отдельные линии для удобство чтения.

Вызывая this.setState внутри обработчика onClick , мы обновляем указанное значение. После обновления значение this.state.value будет ‘X’ , и мы увидите X на игровой доске. Если сейчас вы кликните на любой компонент Square, на нем должен отобразиться X .

Инструменты разработчика (Опционально)

React Devtools это расширение для Chrome и Firefox которые позволяет вам контролировать дерево компонентов React в вашем браузере.

После установки React DevTools вы можете щелкнуть правой кнопкой мыши по любому элементу на странице, нажать «Проверить», чтобы открыть инструменты разработчика, и вкладка React появится в качестве последней вкладки справа.

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

  1. Залогинится или зарегистрироваться и подтвердить свой email (требуется для предотвращения спама).
  2. Нажать на кнопку “Fork”.
  3. Нажать на “Change View” и затем выбрать “Debug mode”.
  4. В новой вкладке которая откроется, должен отобразится вкладка React.

Завершение создание игры

Теперь у нас есть основные строительные блоки для нашей игры в крестики-нолики. Чтобы завершить игру, нам нужно чередовать размещение “X” и “O” на доске, и нам нужен способ определить победителя.

Поднятие state вверх

В настоящее время каждый компонент Square поддерживает state. Чтобы определить победителя, нам нужно контролировать значение каждого из 9 квадратов в одном месте.

Как вариант мы можем сделать так что бы компонент Board опрашивал каждый компонент Square и получало бы его state. Хотя такой подход возможен в React, он будет не самым эффективным, а код станет трудным для понимания. Вместо этого лучше сохранять состояние (state) игры в родительском компоненте Board, а не в каждом Square. Пусть лучше компонент Board будет указывать каждому Square, что отображать, передавая prop, точно так же, как мы делали, когда передавали число в каждый квадрат.

Что бы собрать данные от нескольких дочерних компонентов или чтобы два дочерних компонента взаимодействовали друг с другом, вам нужно объявить общее состояние (state) в их родительском компоненте . Родительских компонент может передавать state дочерним компонентам используя props; это позволит синхронизировать все дочерние компоненты друг с другом.

Поднятие состояния (state) в родительский компонент является обычной практикой при рефакторинге компонентов React – давайте сделаем то же самое. Мы добавим constructor в Board и установим начальное состояние state, чтобы оно содержало массив с 9 нулями. Эти 9 нулей будут соответствовать 9 клеткам:

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

Ранее для отображение значений внутри Square, мы передавали value через prop со значениями от 0 до 8 в каждом Square. В предыдущем шаге, мы заменили числа на “X”.

Теперь мы снова используем механизм prop. Мы изменим Board, так чтобы проинформировать каждый отдельный Square о его текущем значении value ( ‘X’ , ‘O’ , or null ). Мы уже определили массив squares в конструкторе Board, и теперь изменим метод renderSquare :

Теперь каждый Square получит value значение которого будет одним из ‘X’ , ‘O’ , или null для пустых squares.

Далее, нам нужно определить то что будет происходит при клике на Square . Теперь компонент Board будет определять какое значение будет у squares. Нам нужно создать способ обновления состояния Square при обновление состояния Board. Так же нам будет нужна такая связь что бы при обновление состояния внутри Square обновлялась значение в Board. Но так как state рассматривается как приватная часть компонента мы не можем обновить state Board напрямую из Square.

Чтобы сохранить приватность state Board, мы передадим функцию от Board в Square. Эта функция будет вызываться при нажатии на Square. Для этого мы изменим метод renderSquare компонента Board:

Теперь мы передадим два props от Board в Square: value и onClick . prop onClick функция которая вызывается при клики на Square. Далее сделаем следующие изменения в Square:

  • Заменим this.state.value на this.props.value в методе render Square
  • Заменим this.setState() на this.props.onClick() в методе render Square
  • Удалим constructor из Square потому что Square больше не отслеживаем состояние игры

После всех этих изменений компонент Square должен выглядит так:

Далее подробное описание того что мы сделали:

  1. Свойство onClick встроенного в DOM компонента говорит React установить обработчик клика.
  2. Когда на кнопку кликают, React вызывает обработчик onClick которые определен в методе render() компонента Square.
  3. Этот обработчик вызывает this.props.onClick() . Метод onClick определенное в Board и передан в Square через props.
  4. Так как Board передает onClick= <() =>this.handleClick(i)> в Square, то при клике на Square вызывается this.handleClick(i) .
  5. Но мы пока еще не определили метод handleClick() , и при попытки запустить наш код мы получим ошибку.

Внутри пользовательским компонентов таких как Square, вы можете выбирать любые имена для свойств и методов. Мы можем назвать свойство onClick или метод handleClick любым именем. Однако в React, используется следующие соглашения о именование событий on[Event] и методов обработчиков handle[Event] .

И так добавим метод handleClick в классе Board:

После этих изменений мы снова можем кликать на Square, чтобы отобразить значения на них. Однако теперь состояние сохраняется в компоненте Board вместо отдельных компонентов Square. При изменении состояния Board компоненты Square автоматически перерисовываются. Сохранение состояния всех квадратов в компоненте Board позволит определить победителя в будущем. В терминах React компоненты Square теперь являются контролируемыми компонентами.

Обратите внимание что в handleClick , мы вызываем .slice() для создания копии массива squares и только потом редактирования в нем а не сразу редактирования исходного массива. Мы объясним почему мы создали копию массива squares в следующей секции.

Почему Immutability (“Неизменяемость”) важна

Существует два подхода к редактированию данных. Первый подход называется mutate то есть данные меняются напрямую. А второй подход называется immutability, он заключается в внесение изменений в копию данных и сохранения исходных данных не тронутыми.

Изменения данных напрямую


Измении копии данных

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

Сложные функции становятся простыми

Неизменность делает сложные функции намного проще для реализации. Позже в этом уроке мы реализуем функцию “time travel” (“путешествие во времени”), которая позволит просмотреть историю игры в крестики-нолики и возможность «вернутся» к предыдущим ходам. Эта функциональность не является специфичной для игр – способность отменять и повторять определенные действия является распространенным требованием в приложениях. Если мы не будет напрямую редактировать данные, мы сможем сохранять предыдущие версии истории игры и использовать их позже.

Обнаружение изменений

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

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

Определение того, когда нужно перерисовать объект в React

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

Функциональные компоненты

Теперь мы преобразуем Square в функциональный компонент.

В React, функциональные компоненты это такие компоненты которые содержать только метод render и не содержит их собственное состояние state. Вместо того что бы создавать класс на основе React.Component , мы можем написать функцию которая принимает props в качестве аргументов и возвращает то что должно быть визуализировано методом render. Функциональные компоненты как правило более простые чем классы.

Заменим класс Square на функцию:

Когда мы изменили Square на функциональный компонент, мы так же изменили onClick= <() =>this.props.onClick()> на более короткую запись onClick= (обратите внимание на отсутствие скобок с обеих сторон). В классе, мы использовали стрелочную функцию для доступа к значению this , но в функциональном компоненте нам не нужно использовать this .

Переход хода

Теперь нам нужно исправить очевидный дефект в нашей игре: мы не может поставить букву “O” на доску.

По умолчанию первый ход за «X». Добавим в конструктор класса Board новую переменную xIsNext отвечающую за переход хода:

Каждый раз когда игрок ходит, xIsNext (a boolean) будет переключать свое состояние для того что бы определить какой игрок делает следующий ход. Мы обновим функцию handleClick так что бы переключать значение xIsNext сразу после окончания хода:

Теперь каждый раз при клике будет сменяться ход. Давайте также изменим текст “status” в методе render Board, чтобы он отображал, какой игрок должен сделать следующий ход:

После применения этих изменений Board должен выглядить следующим образом:

Определение победителя

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

Для определение победы вызовим calculateWinner(squares) в методе render класса Board. Если игрок выиграл, мы отобразим текст “Winner: X” или “Winner: O”. Так же заменим объявление status в методе render следующим кодом:

Сейчас изменим функцию handleClick так что бы при определение победы или при выборе состояния она игнорировала бы дальнейшие клики по Square:

Поздравляем! Теперь у вас есть рабочая игра в крестики-нолики. И вы только что изучили основы React. Так что именно вы стали настоящим победителем в этой игре.

Добавление перемещение по времени

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

Сохранение истории ходов

Если бы мы меняли бы массив squares , то бы наша реализация перемещение по времени была бы достаточной сложной.

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

Сейчас нам надо решить в каком компоненте будет находиться массив history .

Снова поднятие вверх

Мы хотим, чтобы компонент Game верхнего уровня отображал список прошлых ходов. Для этого потребуется доступ к истории, поэтому мы поместим history в компонент Game верхнего уровня. Это так же позволит нам удалить squares из его дочерних компонентов. Подобно тому, как мы “подняли состояние” из компонента Square в Board, сейчас мы поднимим переменную из Board в Game. Это даст компоненту Game полный контроль на данными в Board, и позволит Board рендерить предыдущие хода из history .

Для начало, создадим конструктор в компоненте Game и зададим его начальный state:

Далее сделаем так что бы компонент Board получал squares и свойство onClick от компонента Game. Так как теперь у нас будет один обработчик клика в Board для всех Squares, нам будет нужно передавать расположение каждого Square в обработчик onClick чтобы понимать на каком Square был клик. Внесем следующие изменения в Board:

  • Удалим constructor из Board.
  • Заменим this.state.squares[i] на this.props.squares[i] в renderSquare .
  • Заменим this.handleClick(i) на this.props.onClick(i) в renderSquare .

Компонент Board должен теперь выглядеть следующим образом:

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

Так как компонент Game сейчас отображает статус игры мы можем удалить соотвествующий код из метода render компонента Board. После рефакторинга метод render должен выглядеть так:

И в завершение, нам нужно переместить метод handleClick из компонента Board в компонент Game. Нам так же нужно модифицировать handleClick потому что теперь изменилась структура состояний в Game. В методе handleClick , теперь мы добавляем сделанные ход в history .

В данном коде мы предпочли используем метод concat() , который в отличие метода push() не изменяет начальный массив а создает новый.

На данном шаге компонет Board нуждается только в методах renderSquare и render . Состояние игры и метод handleClick должны быть в компоненты Game.

Отображение прошедших ходов

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

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

Используя метод map , мы можем сопоставить нашу историю ходов с элементами представляющими кнопки на экране, и отобразить список кнопок, чтобы “перейти” к прошлым ходам.

Внесем изменения в метод render копонента Game:

Для каждого хода в истории игры мы создаем элемент списка , который содержит кнопку . Кнопка имеет обработчик onClick, который вызывает метод this.jumpTo(). Мы еще не реализовали метод jumpTo(). Пока что мы должны увидеть список ходов, которые произошли в игре, и предупреждение в консоли инструментов разработчика, которое гласит:

Для каждого хода в истории игры, мы создадим элмент списка
в котором будет кнопка . На кнопке будет обработчик клика onClick который будет вызывать метод this.jumpTo() . Мы пока еще не реализовали метод jumpTo(). Сейчас в браузере мы должны увидеть список ходов, которые произошли в игре, и предупреждение в консоле: Warning: Each child in an array or iterator should have a unique “key” prop. (Каждый дочерний элемент в массиве или итераторе должен иметь уникальное свойство “ключ”.)

Выбор ключа

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

Представьте себе такое изменение

В дополнение к обновленным подсчетам, человек, читающий это, вероятно, сказал бы, что мы поменяли местами Алексу и Бена и вставили Клаудию между Алекса и Бена. Однако React – это компьютерная программа, которая не знает, что мы собираемся сделать. Поскольку React не может знать наши намерения, нам необходимо указать ключ для каждого элемента списка, чтобы отличать каждый элемент списка от других элементов. Одним из вариантов было бы использовать строки alexa, ben, claudia. Если бы мы отображали данные из базы данных, в качестве ключей могли бы использоваться идентификаторы ID элементов Alexa, Ben и Claudia.

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

Ключ key – это специальное, зарезервированное свойство в React (такое же как например ref). Когда элемент создан, React извлекает свойство key и сохраняет непосредственно в возвращаемом элементе. React автоматически использует ключ, чтобы определить, какие компоненты обновлять. Но сам компонент не может получить доступ к своему key . Даже если key может выглядеть так, как будто он принадлежит props, на него нельзя ссылаться, используя this.props.key.

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

Если ключ не указан, React выдаст предупреждение и по умолчанию будет использовать индекс массива в качестве ключа. Использование индекса массива в качестве ключа может быть проблематичным так как при попытке изменить порядок элементов списка или при вставке/удалении элементов списка может возникнуть конфликт. Явное задание key= отключит предупреждение, но имеет те же проблемы, что и индексы массива, и поэтому в большинстве случаев не рекомендуется.

Реализация перемещение по времени

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

В методе render компонента Game, добавим ключ
:

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

Добавим stepNumber: 0 в начальное состояние конструктора Game:

Далее, определим метод jumpTo в Game для обновления stepNumber . Так же назначим xIsNext true если значение в stepNumber четное:

Далее внесем несколько изменений в метод handleClick.

Добавленно нами переменная stepNumber отображает текущий ход пользователя После того как мы сделаем следующий ход, нам нужно обновить stepNumber добавив stepNumber: history.length в качестве аргумента this.setState .

Так же нужно заменить this.state.history на this.state.history.slice(0, this.state.stepNumber + 1) . Это гарантирует что если мы “вернемся назад” а затем сделаем новый ход, мы отбросим все “будущие” состояния в истории потому что они теперь будут не нужны.

Наконец, изменим метод рендеринга компонента Game, чтобы рендеринг последнего хода всегда выполнялся в соответствии с stepNumber :

Завершение

Поздравляем! Вы только что создали игру крестики нолики которая:

  • Позволяет вам играть в крестики-нолики,
  • Определяет состояние, когда игрок выиграл игру,
  • Сохраняет историю игры по ходу игры,
  • Позволяет игрокам просматривать историю игры и просматривать предыдущие версии игрового поля.

Хорошая работа! Мы надеемся, что теперь у вас есть начальные знания того как работать с React.

Если у вас есть время и желание попрактиковаться с React, вот несколько идей по улучшению, которые вы можете внести в игру, которые перечислены в порядке возрастания сложности:

  1. Отобразите местоположение каждого перемещения в формате (столбец, строка) в списке истории перемещений.
  2. Выделите жирным текущий выбранный элемент в списке перемещения.
  3. Перепишите компонент Board, так чтобы использовать два цикла для создания квадратов вместо их жесткого кодирования.
  4. Добавьте кнопку переключения (toggle), которая позволяет сортировать ходы в порядке возрастания или убывания.
  5. Когда кто-то выигрывает, выделите три поля, которые оказались выигрышные.
  6. Когда никто не выигрывает, выведите сообщение о ничье.

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

JavaScript, который нужно знать для React

Дата публикации: 2020-09-24

От автора: одна из вещей, которые мне больше всего нравятся в React по сравнению с другими фреймворками, которые я использовал, это то, насколько вы открыты для JavaScript при его использовании. Шаблон DSL (JSX компилируется в разумный JavaScript) отсутствует, API компонентов стал проще с добавлением React Hooks, и фреймворк предлагает вам очень мало абстракций вне основных проблем пользовательского интерфейса, которые он призван решить.

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

Литералы шаблонов

Литералы шаблонов похожи на обычные строки со сверхспособностями:

Примеры на React. Быстрый старт в изучении React

React строится вокруг концепции компонентов. В отличие от таких фреймворков типа Angular и Ember которые используют двухстороннюю привязку данных для обновления HTML страницы. На мой взгляд, React более прост в освоении, чем Angular и Ember – он намного меньше и хорошо работает с jQuery и другими фреймворками. Он также очень быстрый, потому что он использует виртуальный DOM и синхронизирует только измененные части с основной страницы (доступ к DОМ по-прежнему является медленной часть современного веб-приложения). Однако, обратной стороной является то, что те вещи, которые легко могли бы быть сделаны с помощью привязки данных, занимают немного больше кода в React. В этом вы можете убедиться в приведенных ниже примерах.

Как начать использовать React

Для использования React, вам необходимо включить один файл JavaScript в вашем страницы. Facebook любезно предоставляет нам CDN, на который вы можете сослаться:

Размер файла browser.min.js превышает 1Mb, поэтому такое использование на продакшн строго не рекомендуется!

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

Таймер на React

Как я уже упоминал, приложение на React разбивается на блоки — компоненты. Они создаются путем вызова React.createClass() с объектом опций и методов. Каждый компонент имеет состояние (объект с данными) и каждый отвечает за свой собственной рендеринг — метод render() вызывается всякий раз, когда состояние изменяется. Вот пример создания простого таймера:

Таймер на React JS

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

Навигационное меню на React JS

Давайте посмотрим, как мы можем обработать событие click в React на примере создания меню навигации:

Обратите внимание на атрибут className, которого не существует в HTML. дело в том, что JSX — это JavaScript и такие атрибуты, как class и for неодобряются. Вместо них следует использовать className и htmlFor. Результат работы нашего примера вы можете посмотреть на странице Меню на React.

Мгновенный поиск

Как вам, должно быть, известно, больше всего на свете пользователи не любят долгое ожидание. Вот как можно сеализовать на React функционал для мгновенного поиска.

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

Результат работы нашего примера вы можете посмотреть на странице Мгновенный поиск на React JS.

Форма заказа на React

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

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

Результат работы нашего примера вы можете посмотреть на странице Форма заказа на React JS.

Работа с jQuery и AJAX

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

Обратите внимание: в нашем примере используется один и тот же компонент Picture для отображения списка со всеми изображениям и избранными. Такое неоднократное использование кода является одним из преимуществ React.

Результат работы нашего примера вы можете посмотреть на странице Работа с jQuery и AJAX вReact JS.

Пособие по React: всестороннее изучение React.js

Название книги: React быстро. Веб-приложения на React, JSX, Redux и GraphQL
Автор: Мардан Азат
Год: 2020
Издательство: Питер
ISBN 978-5-4461-0952-4
Страниц: 560
Язык: Русский
Формат: PDF
Размер: 10 Mb

Содержание: Как решить проблемы front-end-разработчиков и сделать их жизнь более счастливой?

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

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

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

Перед вами труд, над которым на протяжении полутора лет работали более дюжины человек.

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

Изучение React и Redux. Level Up

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

Критерий завершения

все поставленные подзадачи выполнены

Личные ресурсы

базовые знания JS, минимальные знания React

Экологичность цели

перспективная библиотека, расширю свои знания о js-технологиях

Мастер Йода рекомендует:  Что нейронная сеть думает о твоем #селфи
Добавить комментарий