React State с нуля

React State с нуля

От автора: как только вы приступите к изучению React, вы столкнетесь с понятием state. State имеет огромное значение в React. Возможно, это первая причина, почему вы стали изучать React. Давайте рассмотрим понятие React state и принцип его работы.

Что такое state?

State (состояние) в React – это объект простого JS, позволяющий отслеживать данные компонента. Состояние компонента может меняться. Смена состояния компонента зависит от функциональности приложения. Изменения могут основываться на ответе от пользователя, новых сообщениях с сервера, ответа сети и т.д.

Состояние компонента должно быть приватным для компонента и контролироваться им. Изменения состояния компонента необходимо делать внутри компонента – инициализация и обновление состояния компонента.

Компоненты класса

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

const App = (props) => { return ( <div> { this.props } </div> )
}

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

class App extends React.Component { constructor(props) { super(props) this.state = { username: 'johndoe' } } render() { const { username } = this.state return( <div> { username } </div> ) }
}

Выше я устанавливаю состояние username компонента в строку.

Конструктор

Судя по официальной документации, инициализация состояния происходит в конструкторе. Инициализация проходит через установку this.state в объект, как сверху. Помните: state – это объект простого JS. Первичное состояние компонента App было задано в объект state, в котором хранится ключ username и значение johndoe (this.state = { username: ‘johndoe’ }).

Инициализация состояния компонента может быть настолько сложной:

constructor(props) { super(props) this.state = { currentTime: 0, status: false, btnOne: false, todoList: [], name: 'John Doe' }
}

Доступ к состоянию

Доступ к инициализированному состоянию можно получить в методе render(), как я сделал сверху.

render() { const { username } = this.state return( <div> { username } </div> )
}

Другой способ:

render() { return( <div> { this.state.username } </div> )
}

Разница в том, что в первом примере я извлек username из состояния, но его можно записать через const status = this.state.username. Благодаря деструктуризации ES6, я не обязан идти таким путем. Не смущайтесь, когда видите такое. Важно знать, что когда я делал это, я не переназначал состояние. Первичные настройки состояния были проведены в конструкторе. Повторно их делать не нужно – никогда не обновляйте состояние компонента напрямую.

Обратиться к состоянию можно this.state.property-name. Не забывайте, что после инициализации состояния для использования this.state необходимо получить доступ к состоянию.

Обновление состояния

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

handleInputChange(username) { this.setState({username})
}

Еще раз, обратите внимание, что я передаю объект в setState(). Далее мне необходимо передать эту функцию в обработчик события, который вызывается при изменении значения поля ввода. Обработчик события предоставит контекст события, которое было вызвано, что позволяет получить значение, введенное в поле, через event.target.value. Это аргумент, переданный в метод handleInputChange(). Метод render должен выглядеть следующим образом.

render() { const { username } = this.state return ( <div> <div> <input type="text" value={this.state.username} onChange={event => this.handleInputChange(event.target.value)} /> </div> <p>Your username is, {username}</p> </div> )
}

При каждом вызове setState() в React отправляется запрос на обновление DOM через обновленное состояние. Теперь вы понимаете, что обновление состояния можно отложить.

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

class App extends React.Component { constructor(props) { super(props) this.state = { username: 'johndoe' } } handleInputChange(username) { this.setState({username}) } render() { const { username } = this.state return ( <div> <div> <input type="text" value={this.state.username} onChange={event => this.handleInputChange(event.target.value)} /> </div> <p>Your username is, {username}</p> </div> ) }
}

Передача состояния в виде свойств

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

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

Начнем с создания первичного состояния компонента.

class App extends React.Component { constructor(props) { super(props) this.state = { todoList: [] } } render() { return() }
}

У состояния компонента есть todoList, заданный в пустой массив. В методе render() я хочу возвращать форму для отправки задач.

render() { const { todoList } = this.state return ( <div> <h2>Enter your to-do</h2> <form onSubmit={this.handleSubmit}> <label>Todo Item</label> <input type="text" name="todoitem" /> <button type="submit">Submit</button> </form> </div > )
}

После ввода и нажатия на кнопку отправки будет вызываться метод handleSubmit. Этот метод будет обновлять состояние компонента. Я буду обновлять состояние путем добавления нового значения в todoList массив через concat. Так будет устанавливаться значение для todoList внутри метода setState(). Как это выглядит:

handleSubmit = (event) => { event.preventDefault() const value = (event.target.elements.todoitem.value) this.setState(({todoList}) => ({ todoList: todoList.concat(value) }))
}

При каждом клике на кнопку отправки получается контекст события. Останавливать стандартное действие отправки, которое перезагружает страницу, будем через event.preventDefault(). Введенное в поле значение присваивается переменной value, которая потом передается как аргумент при вызове todoList.concat(). React обновляет состояние todoList через добавление нового значения в первичный пустой массив. Этот новый массив становится текущим состоянием todoList. Цикл повторяется при добавлении нового элемента.

React State с нуля

Цель – передать отдельный элемент в дочерний компонент в виде свойства. Для этого урока будем называть компонент TodoItem. Вставьте код ниже в родительский div внутри метода render().

<div> <h2>Your todo lists include:</h2> { todoList.map(i => <TodoItem item={i} /> )}
</div>

Мы проходимся в цикле по todoList через map. То есть в компонент TodoItem передается один элемент в виде свойства. Для этого вам нужен компонент TodoItem, который получает свойство и рендерит его в DOM. Я покажу, как сделать это через функциональные компоненты и компоненты класса.

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

const TodoItem = (props) => { return ( <div> {props.item} </div> )
}

Компонент класса:

class TodoItem extends React.Component { constructor(props) { super(props) } render() { const {item} = this.props return ( <div> {item} </div> ) }
}

Если в этом компоненте не нужно управлять состоянием, лучше использовать функциональный компонент.

Повышение уровня

При разработке React приложений вы часто будете обрабатывать состояние. Изучив описанные выше темы вы должны быть уверены в том, что сможете погрузиться в продвинутую часть управления состоянием в React. Для более продвинутого изучения рекомендую официальную документацию React State and Lifecycle, а также Uber React Guide on Props vs State.

Автор: Kingsley Silas

Источник: https://css-tricks.com/

Редакция: Команда webformyself.