React Junior
208 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
Передача параметров в компоненты

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

https://codepen.io/furrycat/pen/eYveVqX?editors=0010

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

Функциональный компонент принимает объект props первым аргументом. Чтобы вывести полученные данные в разметке, используйте фигурные скобки. О JSX-разметке поговорим подробнее в следующий раз.

#началоработы #компоненты #примерыкода #документация
JSX

JSX - это нечто среднее между HTML и JS. Большей частью этот формат похож на HTML, но с некоторыми особенностями из JS.

По умолчанию в браузерах он не обрабатывается, поэтому нужен компилятор - Babel. Он преобразует JSX в обычный JavaScript и исполняет его.

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

Главные особенности работы с JSX:

👉 атрибуты указываются не в kebab-case, а в camelCase, как в JavaScript
👉 вместо class нужно писать className
👉 вместо for (для элементов label) нужно писать htmlFor
👉 обработчики событий на тегах тоже в camelCase

Фрагмент JSX - это обычное JS-выражение, которое можно поместить в переменную и делать с ним другие привычные операции, например, передавать в функции и возвращать из них (как мы делаем в компонентах).

Читать в документации (рус): https://ru.react.js.org/docs/introducing-jsx.html

#началоработы #jsx #документация
Выражения в JSX

Внутри JSX можно использовать различные JS-конструкции и выражения. Для этого предназначены фигурные скобки - все внутри них воспринимается именно как выражение и выполняется. В результате выполнения обычно получается фрагмент JSX или null, если ничего выводить не требуется.

https://codepen.io/furrycat/pen/yLMPKzW?editors=1010

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

#началоработы #jsx #документация
👍1
Вывод списков

Чтобы вывести несколько элементов внутри JSX, их нужно просто собрать в массив. Идеальный метод для этого Array.prototype.map. Он принимает любые данные в виде массива и может превратить их в фрагменты JSX. Полученный массив можно записать в переменную, а можно сразу вывести в JSX.

https://codepen.io/furrycat/pen/vYxpJea?editors=0010

Важно: каждый элемент списка должен иметь уникальный ключ (атрибут key).

#началоработы #jsx #примерыкода #документация
Классовые компоненты

С функциональными компонентами мы уже знакомы: https://yangx.top/react_junior/7

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

https://codepen.io/furrycat/pen/bGqaZdr?editors=0010

Класс должен быть унаследован от React.Component и иметь метод render(), который возвращает разметку компонента.

Название класса так же превращается в тег, который можно использовать в разметке.

И вы по-прежнему можете передавать в компонент пропсы (как атрибуты тега) - теперь они доступы в this.props.

#примерыкода #компоненты #началоработы #документация
Отрисовка компонентов

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

👉 Все начинается с метода ReactDOM.render(), который принимает корневую разметку (обычно в формате JSX) и элемент, в который нужно ее поместить.

👉 Если разметка представляет собой обычные html-теги, они и выводятся как обычные html-теги.

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

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

👉 Если компонент классовый, то React вызывает его метод render(), который опять же возвращает фрагмент разметки.

👉 Все это происходит до того, пока не отрендерится все, что нужно.

#началоработы #компоненты #жизненныйциклкомпонента
Виртуальный DOM

С первого взгляда кажется, что при рендеринге React совершает стандартные операции с DOM-деревом: что-то вставляет, что-то удаляет и т.д.
Нет, в итоге это, конечно, так и есть, но сама техника немного сложнее.

React отдельно хранит "идеальное" представление интерфейса - виртуальное DOM-дерево. Если происходят какие-то изменения, то виртуальный DOM сравнивается с реальным и ищется самый короткий путь для обновления страницы.

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

#началоработы #виртуальныйdom #документация
Состояние

Сейчас мы знаем только один путь вывести что-то на страницу с помощью React - ReactDOM.render. Например, если вы захотите сделать часы/таймер/секундомер, то придется каждую секунду рендерить разметку заново вручную. Это не совсем то, чего мы ждем от крутого фронтенд-фреймворка.

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

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

https://codepen.io/pen?editors=0010

Состояние должно храниться в свойстве класса this.state, а обновлять его нужно с помощью специального метода this.setState.

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

👉 Компонент наследует от React.Component, в конструкторе вызывается super()
👉 Метод tick в обработчике клика нужно явно привязать к компоненту, чтобы не потерялся контекст выполнения
👉
Состояние обновляется только с помощью метода this.setState, простое присваивание останется незамеченным


#началоработы #примерыкода #состояние #ссылки
Передача функции в компонент

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

https://codepen.io/furrycat/pen/GRWOxZv?editors=0010

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

#началоработы #компоненты #документация
Привязка контекста обработчиков

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

https://codepen.io/pen?editors=0010

Если внутри обработчика есть ссылки на компонент (обычно this.props или this.state/this.setState), то важно сохранять контекст, чтобы этот this при вызове ссылался именно на компонент.

Лучше всего это делать прямо в конструкторе.

#началоработы #примерыкода #компоненты #документация
Альтернатива биндингу обработчиков

При установке обработчиков событий в React-компонентах не забываем про сохранение контекста выполнения. Классический метод bind разобран выше. Но есть и альтернативы.

👉 Стрелочные функции

https://codepen.io/furrycat/pen/VwpXROe?editors=0010

Обработчик можно оформить как стрелочную функцию. Так как она будет создана внутри метода render, а следовательно при вызове в качестве this у нее будет сам компонент.

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

👉 Синтаксис общедоступных полей классов

https://codepen.io/furrycat/pen/abJYMrg?editors=0010

Экспериментальная фича, которую нужно отдельно подключать в ваш проект: https://babeljs.io/docs/en/babel-plugin-proposal-class-properties.

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

#началоработы #примерыкода #обработкасобытий #документация
Передача параметров в обработчик события

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

https://codepen.io/furrycat/pen/ExWEJWx?editors=0011

Для этого можно использовать стрелочные функции или привязывать аргументы с помощью метода bind.

#началоработы #примерыкода #обработкасобытий #документация
Асинхронный setState

Вот и первая ошибка новичка 🙂

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

https://codepen.io/furrycat/pen/VwpXNJr?editors=0010

Метод update() делает два вызова setState подряд, каждый из которых увеличивает value на 1. Но в результате мы получаем не 3, как предполагалось, а 2. Два вызова просто превратились в один.

#началоработы #ошибки #состояние #документация #примерыкода
Асинхронный setState. Решение

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

https://codepen.io/furrycat/pen/eYvMaYJ?editors=0010

#началоработы #ошибки #состояние #примерыкода #документация
setState() - что нужно знать

👉 setState - единственный способ изменить состояние компонента. Простое присваивание в this.state работает исключительно в конструкторе.

👉 setState работает асинхронно. Для лучшей производительности несколько вызовов метода могут быть сгруппированы в одно обновление.

👉 В setState нужно передавать только те поля, которые изменились. Неизменные копировать необязательно. Изменения будут сложены со старым состоянием.

#началоработы #состояние #документация
Жизненный цикл компонентов

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

Какие они вообще бывают?

👉 Монтирование (mounting) - первоначальный рендеринг компонента на странице.
👉 Обновление - происходит при изменении пропсов или состояния компонента.
👉 Размонтирование (unmounting) - удаление корневого DOM-узла компонента.
👉 Всплытие ошибок от дочерних компонентов.

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

☑️ constructor() - конструктор классового компонента. Вызывается еще до монтирования. Здесь нужно инициализировать состояние (this.state) и привязывать обработчики событий к экземпляру компонента.

☑️ render() - главный метод компонента, который должен вернуть его разметку.

☑️ componentDidMount() - вызывается сразу после монтирования компонента в DOM. Тут стоит взаимодействовать с DOM-узлами (если нужно) и отправлять сетевые запросы.

☑️ componentDidUpdate() - вызывается после каждого обновления пропсов или состояния компонента (не вызывается при первом рендере). Тут удобно сравнивать текущие данные с предыдущими и делать что-нибудь на этой основе.

☑️ componentWillUnmount() - вызывается перед размонтированием компонента. Тут нужно очищать память, сбрасывать все таймеры и подписки.

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

Ссылка на документацию (рус): https://ru.reactjs.org/docs/react-component.html#the-component-lifecycle

#началоработы #компоненты #жизненныйциклкомпонента
Пропсы - только для чтения

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

#важно #компоненты #началоработы #документация
Однонаправленный поток данных

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

При этом внутреннее состояние компонента изолировано внутри него. То есть оно не видно ни его родителям, ни его детям.

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

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

#началоработы #потокданных #компоненты #документация
Подъем состояния

Статья из документации (рус.): https://ru.reactjs.org/docs/lifting-state-up.html

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

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

👉 главный компонент Calculator, который непосредственно выполняет пересчет
👉 два компонента - поля для ввода температуры
👉 компонент с сообщением о том, достаточно ли указанной температуры для кипения воды

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

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

#началоработы #состояние #потокданных #документация
Предотвращение рендеринга

Иногда компонент может НИЧЕГО не выводить на страницу, прятаться, несмотря на то, что он был отрендерен другим компонентом. Это часто требуется для сообщений об ошибках.

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

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

#началоработы #компоненты #документация
Условный рендеринг

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

Мы уже разбирались, что в JSX можно использовать любые валидные JavaScript-выражения. В том числе и самые разные условия. Быстро пробежимся по вариантам.

👉 Вне JSX

https://codepen.io/furrycat/pen/YzZLrzE?editors=0010

Мы всегда можем произвести все нужные операции ДО инструкции return (в теле функционального компонента или метода render классового компонента). Здесь можно использовать любые JS-конструкции, включая if и switch.

Вычислив нужный компонент, просто поместите его в переменную и выведите в JSX в return.

👉 Внутри JSX

Внутри JSX можно использовать только ВЫРАЖЕНИЯ, то есть if не подходит. Вместо него подойдут:

☑️ оператор логического сложения &&. Подходит, если вам нужно вывести или скрыть какой-то компонент в зависимости от условия.

https://codepen.io/furrycat/pen/ExWLway?editors=0010

☑️ тернарный оператор. Дает возможность выбрать между двумя вариантами.

https://codepen.io/furrycat/pen/MWpGEwW?editors=0010

Главное, не стремиться все запихнуть в JSX. Большие и сложные выражения лучше выносить в тело функции для лучшей читаемости.

#началоработы #jsx #примерыкода #документация