Состояние и жизненный цикл
В предыдущих уроках мы узнали, что единственный способ обновить пользовательский интерфейс - вызвать метод ReactDOM.render ().
В этом уроке мы рассмотрим концепцию состояния, это мы сделаем, переписав пример тикающих часов из предыдущего урока.
function tick() {
const element = (
<div€
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root') );
}
setInterval(tick, 1000);
Мы можем начать с инкапсуляции того, как часы выглядят, разбив вышеперечисленное на биты:
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
Тем не менее, он пропускает важнейшее требование: тот факт, что Clock устанавливает таймер и обновляет пользовательский интерфейс каждую секунду, должен быть деталью реализации Clock.
В идеале мы хотим написать это один раз, а сами часы обновятся:
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Чтобы реализовать это, нам нужно добавить «состояние» к компоненту Clock.
Состояние похоже на реквизит, но оно является частным и полностью контролируется компонентом и его изменяемым компонентом. Оно может использоваться только в компонентах класса. Таким образом, мы должны преобразовать вышеуказанный компонент функции Clock в компонент класса.
Преобразование функции в класс
Вы можете преобразовать компонент функции, такой как Clock, в класс за пять шагов:
- Создайте класс ES6 с тем же именем, который расширяет React.Component.
- Добавьте к нему один пустой метод с именем render ().
- Переместите тело функции в метод render ().
- Замените реквизиты на this.props в теле render ().
- Удалите оставшееся пустое объявление функции.
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Часы теперь определены как класс, а не функция.
Метод рендеринга будет вызываться каждый раз, когда происходит обновление, но пока мы рендерим
Добавление локального состояния в класс
Мы переместим дату из реквизита в состояние в три этапа:
- Замените this.props.date на this.state.date в методе render ():
- Добавьте конструктор класса, который назначает начальный this.state:
- Удалите опору даты из элемента <Clock />:
Окончательный пример кода выглядит так:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div€
<h1>Hello, world!>/h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Далее, мы заставим Часы настроить собственный таймер и обновлять себя каждую секунду.
Добавление методов жизненного цикла в класс
В приложениях со многими компонентами очень важно высвободить ресурсы, используемые компонентами при их уничтожении.
Мы хотим установить таймер всякий раз, когда Clock отображается в DOM в первый раз. Это называется "монтаж" в React.
Мы также хотим очистить этот таймер при удалении DOM, созданного Clock. Это называется «размонтирование» в React.
Мы можем объявить специальные методы в классе компонента для запуска некоторого кода, когда компонент монтируется и демонтируется:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Эти методы называются «методы жизненного цикла».
Метод componentDidMount () запускается после визуализации вывода компонента в DOM. Это хорошее место для настройки таймера:
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
Обратите внимание, как мы сохраняем ID таймера прямо на этом.
Хотя this.props устанавливается самим React, а this.state имеет особое значение, вы можете добавлять дополнительные поля в класс вручную, если вам нужно сохранить что-то, что не участвует в потоке данных (например, идентификатор таймера). ).
Мы разобьем таймер в методе жизненного цикла componentWillUnmount ():
componentWillUnmount() {
clearInterval(this.timerID);
}
Наконец, мы реализуем метод tick (), который будет запускаться компонентом Clock каждую секунду.
Он будет использовать this.setState () для планирования обновлений локального состояния компонента:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Теперь часы тикают каждую секунду.
Давайте быстро вспомним, что происходит, и порядок вызова методов:
- Когда <Clock /> передается в ReactDOM.render (), React вызывает конструктор компонента Clock. Поскольку Clock необходимо отображать текущее время, он инициализирует this.state объектом, включающим текущее время. Мы позже обновим это состояние.
- Затем React вызывает метод render () компонента Clock. Вот как React узнает, что должно отображаться на экране. Затем React обновляет DOM, чтобы он соответствовал выводу часов.
- Когда вывод Clock вставлен в DOM, React вызывает метод жизненного цикла componentDidMount (). Внутри него компонент Clock просит браузер настроить таймер для вызова метода tick () компонента один раз в секунду.
- Каждую секунду браузер вызывает метод tick (). Внутри него компонент Clock планирует обновление пользовательского интерфейса, вызывая setState () с объектом, содержащим текущее время. Благодаря вызову setState () React знает, что состояние изменилось, и снова вызывает метод render (), чтобы узнать, что должно быть на экране. На этот раз this.state.date в методе render () будет другим, поэтому выходные данные рендера будут содержать обновленное время. Реагируйте обновления DOM соответственно.
- Если компонент Clock когда-либо удаляется из DOM, React вызывает метод жизненного цикла componentWillUnmount (), поэтому таймер останавливается.
Использование государства правильно
Есть три вещи, которые вы должны знать о setState ().
Не изменяйте состояние напрямую
Например, это не будет повторно визуализировать компонент:
// Wrong
this.state.comment ='Hello';
Instead, use setState():
// Correct
this.setState({comment: 'Hello'});
Единственное место, где вы можете назначить this.state - это конструктор.
Обновления состояния могут быть асинхронными
React может объединять несколько вызовов setState () в одно обновление для повышения производительности.
Поскольку this.props и this.state могут обновляться асинхронно, вы не должны полагаться на их значения для вычисления следующего состояния.
Например, этот код может не обновить счетчик:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
Чтобы исправить это, используйте вторую форму setState (), которая принимает функцию, а не объект. Эта функция получит предыдущее состояние в качестве первого аргумента, а реквизиты во время применения обновления в качестве второго аргумента:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
We used an arrow function above, but it also works with regular functions:
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
Новый контент: Composer: менеджер зависимостей для PHP , R программирования