fbpx

Каталог статей

Каталог статей для размещения статей информационного характера

Как выучить

Учебное пособие: Введение в React

Учебное пособие: Введение в React

Этот учебник не предполагает наличия каких-либо знаний о React.

Перед началом урока

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

Совет

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

Учебник разделен на несколько разделов:

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

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

Что мы создаем?

В этом уроке мы покажем, как создать интерактивную игру “Крестики-нолики” с помощью React.

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

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

Вы можете закрыть игру “Крестики-нолики”, как только ознакомитесь с ней. В этом уроке мы начнем с более простого шаблона. Следующим шагом мы подготовим вас к тому, чтобы вы могли начать создавать игру.

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

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

Подготовка к уроку

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

Вариант установки 1: Написать код в

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

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

Убедитесь, что у вас установлена последняя версия Node.js.

Следуйте инструкциям по установке Create React App, чтобы создать новый проект.

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

Примечание:

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

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

Теперь, если вы запустите npm start в папке проекта и откроете http://localhost:3000 в браузере, вы увидите пустое поле для игры в крестики-нолики.

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

  1. Если вы застряли, обратитесь к ресурсам поддержки сообщества. В частности, чат Reactiflux – отличный способ быстро получить помощь. Если вы не получите ответа или останетесь в затруднительном положении, оформите проблему, и мы вам поможем.
  2. Теперь, когда все готово, давайте познакомимся с React!
  3. React – это декларативная, эффективная и гибкая библиотека JavaScript для создания пользовательских интерфейсов. Она позволяет создавать сложные пользовательские интерфейсы из небольших и изолированных частей кода, называемых “компонентами”.

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

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

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

Метод render возвращает описание того, что вы хотите увидеть на экране. React принимает описание и отображает результат. В частности, render возвращает элемент React , который является облегченным описанием того, что нужно отобразить. Большинство разработчиков React используют специальный синтаксис, называемый “JSX”, который облегчает написание этих структур. Во время сборки синтаксис преобразуется в React.createElement(‘div’) . Приведенный выше пример эквивалентен:

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

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

Компонент ShoppingList выше отображает только встроенные компоненты DOM, такие как и . Но вы можете составлять и отображать и пользовательские компоненты React. Например, теперь мы можем ссылаться на весь список покупок целиком

Этот стартовый код – основа того, что мы создаем. Мы обеспечили стилизацию CSS, чтобы вам нужно было сосредоточиться только на изучении React и программировании игры “крестики-нолики”.

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

Компонент Square рендерит один квадрат, а Board рендерит 9 квадратов. Компонент Game отображает доску со значениями-заполнителями, которые мы изменим позже. В настоящее время нет никаких интерактивных компонентов.

Передача данных через реквизиты

Чтобы прочувствовать, что такое интерактивность, давайте попробуем передать некоторые данные от компонента Board к компоненту Square.

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

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

Измените метод рендеринга Square, чтобы показать это значение, заменив

на :

After: В результате рендеринга в каждом квадрате должно появиться число.

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

Создание интерактивного компонента

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

Если вы сейчас щелкните по квадрату, то в консоли devtools вашего браузера должно появиться сообщение ‘click’.

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

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

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

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

Сначала добавим в класс конструктор для инициализации состояния:

Примечание

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

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

Notice how with onClick= console.log(‘click’)> , we’re passing a function as the onClick prop. React will only call this function after a click. Forgetting () =>Замените this.props.value на this.state.value внутри тега.

Поместите реквизиты className и onClick на отдельные строки для лучшей читабельности.

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

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

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

После установки React DevTools вы можете щелкнуть правой кнопкой мыши на любом элементе на странице, нажать “Inspect”, чтобы открыть инструменты разработчика, и вкладки React (“⚛️ Components” и “⚛️ Profiler”) появятся как последние вкладки справа. Используйте “⚛️ Компоненты” для просмотра дерева компонентов.

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

  • Войдите в систему или зарегистрируйтесь и подтвердите свой email (требуется для предотвращения спама).
  • Replace the onClick= event handler with onClick= this.setState()> .
  • Нажмите кнопку “Fork”.

Нажмите “Изменить вид”, а затем выберите “Режим отладки”.

В открывшейся вкладке devtools должна появиться вкладка React.

Завершение игры

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

Поднятие состояния

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

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

  1. Чтобы собрать данные от нескольких дочерних компонентов или чтобы два дочерних компонента взаимодействовали друг с другом, необходимо объявить общее состояние в их родительском компоненте. Родительский компонент может передавать состояние обратно дочерним компонентам с помощью реквизитов; таким образом дочерние компоненты синхронизируются друг с другом и с родительским компонентом.
  2. Передача состояния в родительский компонент часто встречается при рефакторинге компонентов React – давайте воспользуемся этой возможностью и опробуем ее.
  3. Добавьте конструктор к доске и задайте начальное состояние доски, чтобы она содержала массив из 9 нулей, соответствующих 9 квадратам:
  4. Когда мы позже заполним доску, массив this.state.squares будет выглядеть примерно так:

Метод renderSquare доски в настоящее время выглядит следующим образом:

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

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

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

Далее нам нужно изменить то, что происходит при нажатии на квадрат. Компонент Board теперь поддерживает заполнение квадратов. Нам нужно создать способ для квадрата обновить состояние доски. Поскольку состояние считается частным для компонента, который его определяет, мы не можем обновлять состояние доски непосредственно из Square.

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

Примечание

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

Теперь мы передаем два реквизита от Board к Square: value и onClick . Реквизит onClick – это функция, которую Square может вызвать при нажатии на кнопку мыши. Внесем следующие изменения в Square:

Заменим this.state.value на this.props.value в методе рендеринга Square.

Заменим this.setState() на this.props.onClick() в методе рендеринга Square.

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

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

При нажатии на Square вызывается функция onClick, предоставленная Board. Вот обзор того, как это достигается:

Реквизит onClick на встроенном компоненте DOM говорит React установить слушателя события click.

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

Этот обработчик события вызывает this.props.onClick() . Реквизит onClick Square был задан Советом директоров.

При нажатии на Square, Square вызывает handleClick(i) Board.

  • Мы еще не определили метод handleClick(), поэтому наш код аварийно завершается. Если вы сейчас щелкните по квадрату, вы должны увидеть красный экран ошибки, говорящий что-то вроде “this.handleClick не является функцией”.
  • Обратите внимание на .
  • Атрибут onClick элемента DOM имеет особое значение для React, потому что это встроенный компонент. Для пользовательских компонентов, таких как Square, именование зависит от вас. Мы можем дать любое имя атрибуту onClick Square или методу handleClick Board, и код будет работать одинаково. В React принято использовать имена on[Event] для реквизитов, которые представляют события, и handle[Event] для методов, которые обрабатывают события.

Когда мы попытаемся нажать на квадрат, мы должны получить ошибку, потому что мы еще не определили handleClick. Теперь мы добавим handleClick в класс Board:

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

  1. Поскольку компоненты Square больше не поддерживают состояние, компоненты Square получают значения от компонента Board и информируют компонент Board, когда на них нажимают. В терминах React компоненты Square теперь являются управляемыми компонентами. Совет имеет полный контроль над ними.
  2. Обратите внимание, как в handleClick мы вызываем .slice(), чтобы создать копию массива квадратов для изменения, вместо того чтобы изменять существующий массив. Мы объясним, почему мы создаем копию массива квадратов в следующем разделе.
  3. Почему важна неизменяемость
  4. Since the Board passed onClick= this.handleClick(i)>В предыдущем примере кода мы предложили создать копию массива квадратов с помощью метода slice() вместо того, чтобы модифицировать существующий массив. Теперь мы обсудим i
  5. Неизменяемость значительно облегчает реализацию сложных функций. Позже в этом учебнике мы реализуем функцию “путешествия во времени”, которая позволит нам просматривать историю игры в крестики-нолики и “возвращаться” к предыдущим ходам. Эта функциональность не является специфической для игр – возможность отмены и повторения определенных действий является обычным требованием в приложениях. Избегая прямой мутации данных, мы можем сохранить предыдущие версии истории игры и использовать их в дальнейшем.

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

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

Определение момента повторного рендеринга в React

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

Подробнее о функции shouldComponentUpdate() и о том, как создавать чистые компоненты, вы можете узнать, прочитав статью Оптимизация производительности.

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

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

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

Мы изменили this.props на props оба раза, когда она появляется.

Обратите внимание на

на более короткое onClick= (обратите внимание на отсутствие круглых скобок с обеих сторон).

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

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

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

С помощью этого изменения “Х” и “О” смогут ходить по очереди. Попробуйте!

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

После применения этих изменений у вас должен получиться такой компонент Board:

Объявление победителя

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

Учитывая массив из 9 квадратов, эта функция будет проверять наличие победителя и возвращать ‘X’, ‘O’ или null в зависимости от ситуации.

Мы вызовем calculateWinner(squares) в функции рендеринга доски, чтобы проверить, выиграл ли игрок. Если игрок выиграл, мы можем вывести на экран текст, например, “Winner

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

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

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

When we modified the Square to be a function component, we also changed onClick= this.props.onClick()>Однако мы использовали функцию slice() для создания новой копии массива квадратов после каждого хода и рассматривали его как неизменяемый. Это позволит нам хранить все прошлые версии массива квадратов и перемещаться между уже произошедшими ходами.

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

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

Подъем состояния вверх, снова

Мы хотим, чтобы компонент Game верхнего уровня отображал список прошлых ходов. Для этого ему понадобится доступ к истории, поэтому мы поместим состояние истории в компонент Game верхнего уровня.

Поместив состояние истории в компонент Game, мы сможем удалить состояние квадратов из его дочернего компонента Board. Точно так же, как мы “поднимали состояние вверх” из компонента Квадрат в компонент Доска, теперь мы поднимаем его из Доски в компонент Игра верхнего уровня. Это дает компоненту Game полный контроль над данными доски и позволяет ему инструктировать доску для отображения предыдущих ходов из истории.

Сначала мы установим начальное состояние компонента Game в его конструкторе:

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

Удалите конструктор в Board.

Замените this.state.squares[i] на this.props.squares[i] в рендере Board’s renderSquare .

Замените this.handleClick(i) на this.props.onClick(i) в рендере Board .

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

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

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

Наконец, нам нужно перенести метод handleClick из компонента Board в компонент Game. Нам также нужно изменить handleClick, потому что состояние компонента Game структурировано по-другому. В методе handleClick компонента Game мы объединяем новые записи истории в history .

Обратите внимание на .

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

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

Показ прошлых движений

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

Ранее мы узнали, что элементы React являются первоклассными объектами JavaScript; мы можем передавать их в наших приложениях. Чтобы отобразить несколько элементов в React, мы можем использовать массив элементов React.

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

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

Давайте отобразим историю в методе рендеринга игры:

Когда мы итерируем массив history, переменная step ссылается на текущее значение элемента history, а move – на текущий индекс элемента history. Здесь нас интересует только move, поэтому step ничему не присваивается.

  • Предупреждение: Каждый дочерний элемент в массиве или итераторе должен иметь уникальный “ключевой” параметр. Проверьте метод рендеринга “Game”.
  • Давайте обсудим, что означает вышеуказанное предупреждение.
  • Когда мы выводим список, React сохраняет некоторую информацию о каждом выведенном элементе списка. Когда мы обновляем список, React должен определить, что изменилось. Мы могли добавить, удалить, перегруппировать или обновить элементы списка.

Представьте себе переход от

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

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

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

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

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

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

Реализация путешествия во времени

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

И предупреждение React о ключах должно исчезнуть:

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

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

Далее мы определим метод jumpTo в Game для обновления этого stepNumber. Мы также установим xIsNext в true, если число, на которое мы меняем stepNumber, четное:

Обратите внимание, что в методе jumpTo мы не обновили свойство history состояния. Это потому, что обновления состояния объединяются или, проще говоря, React будет обновлять только свойства, упомянутые в методе setState, оставляя остальное состояние как есть. Более подробную информацию можно найти в документации.

Теперь мы внесем несколько изменений в метод Game’s handleClick, который срабатывает, когда вы нажимаете на квадрат.

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

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

Наконец, мы изменим метод рендеринга компонента Game, который будет всегда рендерить последний ход, на рендеринг текущего выбранного хода в соответствии с шагомNumber :

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

Поздравляем! Вы создали игру “Крестики-нолики”, которая:

Позволяет играть в крестики-нолики,

Показывает, когда игрок выиграл партию,

Сохраняет историю игры по мере ее прохождения,

позволяет игрокам просматривать историю игры и видеть предыдущие версии игрового поля.

Отличная работа! Надеемся, теперь вы чувствуете, что у вас есть достаточное представление о том, как работает React.

Ознакомьтесь с окончательным результатом здесь: Final Result .

In the Game component’s render method, we can add the key as >Если у вас есть свободное время или вы хотите попрактиковаться в своих новых навыках React, вот несколько идей по улучшению игры в крестики-нолики, которые перечислены в порядке возрастания сложности:

Отображать местоположение каждого хода в формате (col, row) в списке истории ходов.

Выделить жирным шрифтом текущий выбранный элемент в списке ходов.

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

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

Когда кто-то выигрывает, выделять три квадрата, которые привели к победе.

Когда никто не выигрывает, выведите сообщение о том, что результат ничейный.

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

React Devtools

React Devtools

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *