Вернуться

Учебный курс по React, часть 15: практикумы по работе с состоянием компонентов


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

Учебный курс по React, часть 12: практикум, третий этап работы над TODO-приложением

→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов

Занятие 27. Практикум. Состояние компонентов, отладка

▍Задание

Проанализируйте представленный ниже код класса App из файла App.js стандартного React-приложения, созданного средствами create-react-app. Этот код неполон, в нём есть ошибки.

import React from "react"

class App extends Component() {
    return (
        <div>
            <h1>{this.state.name}</h1>
            <h3><font color="#3AC1EF">▍{this.state.age} years old</font></h3>
        </div>
    )    
}

export default App

У компонента App, основанного на классе, нет конструктора, его состояние не инициализировано, но при формировании того, что он возвращает, подразумевается наличие у него состояния с некими данными.

Ваша задача заключается в том, чтобы привести этот код в работоспособное состояние.

Если вы столкнётесь с неким неизвестным вам сообщением об ошибке — не спешите заглядывать в решение. Попытайтесь самостоятельно, например, внимательно вчитавшись в код и поискав сведения о проблеме в интернете, выяснить причину ошибки и её исправить. Отладка кода — ценнейший навык, который обязательно пригодиться вам при работе над реальными проектами.

▍Решение

Тело класса похоже на тело функционального компонента. В нём имеется лишь команда return, но в компонентах, основанных на классах, эта команда используется в методе render(), а не в теле класса. Исправим это.

import React from "react"
class App extends Component() {
    render() {
        return (
            <div>
                <h1>{this.state.name}</h1>
                <h3><font color="#3AC1EF">▍{this.state.age} years old</font></h3>
            </div>
        )    
    }
}

export default App

Если продолжить анализ кода, поглядывая на сообщения об ошибках, выводимые в браузере, можно понять, что хотя конструкция class App extends Component выглядит вполне нормально, с тем, к чему мы обращаемся по имени Component, всё ещё что-то не так. Проблема заключается в том, что в команде импорта, import React from "react", мы импортируем в проект лишь React, но не Component. То есть, нам надо либо отредактировать эту команду, приведя её к виду import React, {Component} from "react", тогда при создании класса мы сможем воспользоваться уже существующим кодом, либо переписать объявление класса в таком виде: class App extends React.Component. Мы остановимся на первом варианте. Теперь код компонента выглядит так:

import React, {Component} from "react"

class App extends Component() {
    render() {
        return (
            <div>
                <h1>{this.state.name}</h1>
                <h3><font color="#3AC1EF">▍{this.state.age} years old</font></h3>
            </div>
        )    
    }
}

export default App

Правда, на этом проблемы не заканчиваются. Приложение не работает, в браузере появляется сообщение об ошибке TypeError: Cannot set property 'props' of undefined, нам сообщают, что что-то не так с первой строкой объявления класса.

Дело тут в том, что при объявлении компонента, который, как мы уже поняли, является компонентом, который основан на классе, после имени родительского класса стоит пара круглых скобок. Они тут не нужны, это не функциональный компонент, поэтому от них мы избавимся. Теперь код приложения оказывается более или менее работоспособным, компонент, основанный на классе, уже не выглядит совершенно неправильным, но система продолжает сообщать нам об ошибках. Теперь сообщение об ошибке выглядит так: TypeError: Cannot read property 'name' of null. Очевидно, оно относится к попытке использования данных, хранящихся в состоянии компонента, которое пока не инициализировано. Поэтому теперь мы создадим конструктор класса, не забыв вызвать в нём super(), и инициализируем состояние компонента, добавив в него значения, с которыми компонент пытается работать.

Вот готовый рабочий код компонента App:

import React, {Component} from "react"

class App extends Component {
    constructor() {
        super()
        this.state = {
            name: "Sally",
            age: 13
        }
    }
    
    render() {
        return (
            <div>
                <h1>{this.state.name}</h1>
                <h3><font color="#3AC1EF">▍{this.state.age} years old</font></h3>
            </div>
        )    
    }
}

export default App

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

Страница приложения в браузере

Страница приложения в браузере

Занятие 28. Практикум. Состояние компонентов, работа с данными, хранящимися в состоянии

На этом практическом занятии у вас будет ещё один шанс поработать с состоянием компонентов. 

▍Задание

Ниже приведён код функционального компонента. Взяв его за основу, сделайте следующее:

  1. Преобразуйте его так, чтобы у компонента было бы состояние.

  2. В состоянии компонента должно присутствовать свойство isLoggedIn, хранящее логическое значение true, если пользователь вошёл в систему, и false — если нет (в нашем случае никаких механизмов «входа в систему» здесь нет, соответствующее значение нужно установить вручную, при инициализации состояния).

  3. Постарайтесь сделать так, чтобы, если пользователь в систему вошёл, компонент выводил бы текст You are currently logged in, а если нет — то текст You are currently logged out. Это задание является необязательным, если у вас возникнут трудности при его выполнении, можете, например, поискать идеи в интернете.

Вот код файла App.js:

import React from "react"

function App() {
    return (
        <div>
            <h1>You are currently logged (in/out)</h1>
        </div>
    )
}

export default App

▍Решение

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

import React from "react"

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            isLoggedIn: true
        }
    }
    
    render() {
        return (
            <div>
                <h1>You are currently logged (in/out)</h1>
            </div>
        )
    }
}

export default App

Проверим работоспособность приложения.

Приложение в браузере

Приложение в браузере

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

В сущности, то, что нужно сделать для выполнения этого задания, мы будем обсуждать на занятии, которое посвящено условному рендерингу, так что здесь мы немного забегаем вперёд. Итак, мы собираемся объявить и инициализировать переменную, которая будет содержать строку in или out в зависимости от того, что именно хранится в свойстве состояния isLoggedIn. Работать с этой переменной мы будем в методе render(), сначала анализируя данные и записывая в неё нужное значение, а потом используя её в возвращаемом компонентом JSX-коде. Вот что у нас в итоге получилось:

import React from "react"

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            isLoggedIn: true
        }
    }
    
    render() {
        let wordDisplay
        if (this.state.isLoggedIn === true) {
            wordDisplay = "in"
        } else {
            wordDisplay = "out"
        }
        return (
            <div>
                <h1>You are currently logged {wordDisplay}</h1>
            </div>
        )
    }
}

export default App

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

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

Страница приложения в браузере

Страница приложения в браузере

Свойство состояния isLoggedIn установлено в значение true, поэтому на странице выводится текст You are currently logged in. Для вывода текста You are currently logged out нужно поменять, в коде компонента, значение isLoggedIn на false.

Надо отметить, что эту задачу можно решить и другими способами. Но код, который у нас получился, понятен и работоспособен, поэтому мы остановимся на нём, хотя, например, учитывая то, что isLoggedIn — логическая переменная, условие if (this.state.isLoggedIn === true) можно переписать как if (this.state.isLoggedIn).

Итоги

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

16 февраля 2019 г. 15:02

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