Сегодня, в переводе следующей части учебного курса по React, мы предлагаем вашему вниманию второе занятие по условному рендерингу и практикум по этой теме.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
Занятие 37. Условный рендеринг, часть 2
→ Оригинал
На сегодняшнем занятии по условному рендерингу мы поговорим об использовании логического оператора &&
(И). Экспериментировать будем со стандартным проектом, созданным средствами create-react-app, в файле App.js
которого находится следующий код:
import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {
unreadMessages: [
"Call your mom!",
"New spam email available. All links are definitely safe to click."
]
}
}
render() {
return (
<div>
<h2>You have {this.state.unreadMessages.length} unread messages!</h2>
</div>
)
}
}
export default App
Сейчас приложение выглядит в браузере так, как показано ниже.
Страница приложения в браузере
Возможно, вы уже пользовались оператором &&
в конструкциях наподобие true && false
(что даёт false
). Для того, чтобы в результате вычисления подобного выражения было бы возвращено true
, оно должно выглядеть как true && true
. При обработке таких выражений JavaScript определяет, является ли их левая часть истинной, и, если это так, просто возвращает то, что находится в их правой части. Если обрабатывается выражение вида false && false
, то сразу будет возвращено false
, без проверки правой части выражения. В результате оператор &&
можно использовать в условном рендеринге. С его помощью можно либо вернуть что-то, что будет выведено на экран, либо не возвращать ничего.
Проанализируем код учебного приложения.
В состоянии компонента App
хранится массив строк unreadMessages
. Каждая строка в этом массиве представляет собой непрочитанное сообщение. На страницу выводится количество непрочитанных сообщений, определяемое на основе длины массива. Если же этот массив будет пустым, то есть в нём не будет ни одного элемента, то приложение выведет на страницу то, что показано ниже.
Приложение информирует нас о том, что непрочитанных сообщений нет
Для того чтобы добиться такого эффекта, достаточно привести массив к такому виду: unreadMessages: []
.
Если непрочитанных сообщений нет, то вполне можно не выводить вообще никакого сообщения. Если воспользоваться для реализации такого поведения приложения тернарным оператором, о котором мы говорили в прошлый раз, метод render()
компонента App
можно переписать так:
render() {
return (
<div>
{
this.state.unreadMessages.length > 0 ?
<h2>You have {this.state.unreadMessages.length} unread messages!</h2> :
null
}
</div>
)
}
Теперь в том случае, если массив unreadMessages
пуст, на страницу не будет выводиться ничего. Но представленный здесь код можно упростить благодаря использованию оператора &&
. Вот как это будет выглядеть:
render() {
return (
<div>
{
this.state.unreadMessages.length > 0 &&
<h2>You have {this.state.unreadMessages.length} unread messages!</h2>
}
</div>
)
}
Если в массиве что-то есть — на страницу выводится правая часть выражения. Если массив пуст — на страницу не выводится ничего.
Нельзя сказать, что использование оператора &&
в условном рендеринге абсолютно необходимо, так как того же эффекта можно достичь с использованием тернарного оператора, возвращающего null
в том случае, если проверяемое им условие ложно. Но представленный здесь подход упрощает код, и, кроме того, используется он довольно часто, поэтому вы можете столкнуться с ним, читая чужие программы.
Занятие 38. Практикум. Условный рендеринг
→ Оригинал
▍Задание
Вот код функционального компонента App
, который хранится в файле App.js
стандартного проекта, созданного с помощью create-react-app.
import React from "react"
function App() {
return (
<div>
Code goes here
</div>
)
}
export default App
Вам нужно сделать следующее:
- Преобразуйте код компонента так, чтобы оснастить его состоянием.
- Сделайте так, чтобы в состоянии компонента хранились бы сведения о том, «вошёл» ли пользователь в систему или нет (в этом упражнении «вход» в систему и «выход» из неё означает лишь изменение соответствующего значения, хранящегося в состоянии).
- Добавьте на страницу, которую формирует компонент, кнопку, которая позволяет пользователю входить в систему и выходить из неё.
- Это — дополнительное задание. Сделайте так, чтобы, если пользователь не вошёл в систему, на кнопке выводилась бы надпись
LOG IN
, а если вошёл — надписьLOG OUT
.
- Это — дополнительное задание. Сделайте так, чтобы, если пользователь не вошёл в систему, на кнопке выводилась бы надпись
- Выведите на странице, формируемой компонентом, надпись
Logged in
в том случае, если пользователь вошёл в систему, иLogged out
в том случае, если не вошёл.
Если сейчас вы чувствуете, что приступить к решению этих задач вам сложно — взгляните на подсказки, а потом приступайте к работе.
▍Подсказки
Для выполнения этого задания нужно вспомнить многое из того, о чём мы говорили на предыдущих занятиях. Начнём с того, что компонент, который может иметь состояние, должен быть компонентом, который основан на классе. У этого компонента должен быть конструктор. В состоянии компонента можно хранить логическое свойство, например, его можно назвать isLoggedIn
, значение которого, true
или false
, указывает на то, вошёл пользователь в систему или нет. Для того чтобы кнопка, которую нужно добавить на страницу, генерируемую приложением, могла бы выполнять свои функции, ей понадобится обработчик события onClick
. Для того чтобы выводить разные тексты, опираясь на изменяющееся значение состояния, нужно будет прибегнуть к технологии условного рендеринга.
▍Решение
Преобразуем имеющийся в коде функциональный компонент в компонент, основанный на классе. Нам это нужно по нескольким причинам. Во-первых, нам нужно работать с состоянием приложения. Во-вторых, нам нужен обработчик события, вызываемый при щелчке по кнопке. В принципе, можно написать самостоятельную функцию и использовать её для обработки событий кнопки, но я предпочитаю описывать обработчики в пределах классов компонентов.
Вот как будет выглядеть код функционального компонента, преобразованного в компонент, основанный на классе. Здесь же мы, в конструкторе компонента, описываем его первоначальное состояние, которое содержит свойство isLoggedIn
, установленное в значение false
.
import React from "react"
class App extends React.Component {
constructor() {
super()
this.state = {
isLoggedIn: false
}
}
render() {
return (
<div>
Code goes here
</div>
)
}
}
export default App
Вышеприведённый код представляет собой решение первой и второй частей задания. Теперь поработаем над добавлением кнопки на страницу, выводимую компонентом. Пока эта кнопка будет выводить одну и ту же надпись независимо от того, что хранится в состоянии приложения. Мы оснастим её обработчиком события, поместив в него, для проверки работоспособности нашего кода, простую команду вывода сообщения в консоль. Кроме того, мы, в конструкторе компонента, привяжем этот обработчик к this
, что пригодится нам тогда, когда мы будем, в коде этого обработчика, обращаться к механизмам, предназначенным для работы с состоянием компонента. Сейчас код выглядит так, как показано ниже.
import React from "react"
class App extends React.Component {
constructor() {
super()
this.state = {
isLoggedIn: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
console.log("I'm working!")
}
render() {
return (
<div>
<button onClick={this.handleClick}>LOG IN</button>
</div>
)
}
}
export default App
При нажатии на кнопку LOG IN
в консоль попадает текст I’m working!
.
Теперь вспомним о том, что нам надо, чтобы при щелчке по кнопке свойство isLoggedIn
, хранящееся в состоянии, менялось бы с true
на false
и наоборот. Для этого в обработчике щелчка по кнопке нужно будет вызвать функцию this.setState()
, которую можно использовать двумя способами. А именно, ей можно предоставить, в виде объекта, новое представление того, что должно содержаться в состоянии. Второй вариант её использования предусматривает передачу ей функции, которая принимает предыдущее состояние компонента и формирует новое, возвращая, опять же, объект. Мы поступим именно так. Вот что у нас получилось на данном этапе работы.
import React from "react"
class App extends React.Component {
constructor() {
super()
this.state = {
isLoggedIn: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(prevState => {
return {
isLoggedIn: !prevState.isLoggedIn
}
})
}
render() {
return (
<div>
<button onClick={this.handleClick}>LOG IN</button>
</div>
)
}
}
export default App
Тут можно было бы воспользоваться конструкцией if-else, но мы просто преобразовываем значение true
в значение false
, а значение false
в значение true
с использованием логического оператора !
(НЕ).
Пока у нас нет механизма, который, основываясь на том, что хранится в состоянии, позволял бы влиять на внешний вид приложения. Поэтому сейчас мы решим дополнительную задачу задания №3. А именно, сделаем так, чтобы надпись на кнопке менялась бы в зависимости от состояния компонента. Для того чтобы этого добиться, можно объявить в методе render()
переменную, значение которой, LOG IN
или LOG OUT
, зависит от того, что хранится в состоянии. Это значение потом можно использовать в качестве текста кнопки. Вот как это выглядит.
import React from "react"
class App extends React.Component {
constructor() {
super()
this.state = {
isLoggedIn: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(prevState => {
return {
isLoggedIn: !prevState.isLoggedIn
}
})
}
render() {
let buttonText = this.state.isLoggedIn ? "LOG OUT" : "LOG IN"
return (
<div>
<button onClick={this.handleClick}>{buttonText}</button>
</div>
)
}
}
export default App
Теперь займёмся четвёртой частью задания. Будем выводить на страницу текст, зависящий от того, вошёл пользователь в систему или нет. Собственно говоря, учитывая всё то, что уже присутствует в коде компонента, решить эту задачу очень просто. Ниже представлен готовый код файла App.js
.
import React from "react"
class App extends React.Component {
constructor() {
super()
this.state = {
isLoggedIn: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(prevState => {
return {
isLoggedIn: !prevState.isLoggedIn
}
})
}
render() {
let buttonText = this.state.isLoggedIn ? "LOG OUT" : "LOG IN"
let displayText = this.state.isLoggedIn ? "Logged in" : "Logged out"
return (
<div>
<button onClick={this.handleClick}>{buttonText}</button>
<h1>{displayText}</h1>
</div>
)
}
}
export default App
Вот как выглядит приложение в браузере.
Страница приложения в браузере
Щелчок по кнопке LOG IN
, изображённой на предыдущем рисунке, меняет состояние приложения, после чего на кнопке выводится надпись LOG OUT
, а на странице выводится текст, информирующий пользователя о том, что он вошёл в систему.
Итоги
Сегодня мы продолжили разговор об условном рендеринге, рассмотрели использование оператора &&
и выполнили практическое задание, затрагивающее множество изученных нами механизмов. В следующий раз вас ждёт продолжение работы над Todo-приложением и новая тема.
Уважаемые читатели! Справились ли вы с сегодняшним практическим заданием?
Автор: ru_vds