[Разработка веб-сайтов, JavaScript, Программирование, ReactJS] Заметка о том, как React обновляет состояние (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Доброго времени суток, друзья!
Хук useState() управляет состоянием в функциональных компонентах React. В классовых компонентах состояние хранится в this.state, а для обновления вызывается метод this.setState().
Обычно, в работе с состоянием нет ничего сложного. Тем не менее, существует один важный нюанс, связанный с его обновлением.
Каким образом состояние обновляется: незамедлительно (синхронно) или отложенно (асинхронно)? Читайте дальше, чтобы узнать ответ.
1. Обноление состояния с помощью useState()
Допустим у нас имеется такой функциональный компонент:
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncreaseHandler = () => {
setCount(count + 1)
setCount(count + 1)
}
return (
<>
<button onClick={doubleIncreaseHandler}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
const [count, setCount] = useState(0) определяет начальное состояние компонента. count — переменная, содержащая текущее состояние, а setCount — функция обновления этого состояния.
Компонент содержит кнопку Double Increase. При нажатии на эту кнопку вызывается обработчик doubleIncreaseHandler, осуществляющий два последовательных обновления count: setCount(count + 1) и затем еще раз setCount(count + 1).
Каким будет состояние компонента после нажатия кнопки, 1 или 2?
Откройте это демо и нажмите на кнопку. Значение count будет увеличиваться на 1 после каждого клика.
Когда setCount(count + 1) обновляет состояние, значение count не изменяется сразу. Вместо этого, React планирует обновление состояния и при следующем рендеринге в выражении const [count, setCount] = useState(0) хук присваивает count новое значение.
Например: если значением переменной count является 0, то вызов setCount(count + 1); setCount(count + 1) оценивается как setCount(0 + 1); setCount(0 + 1) — что приводит к 1 как значению состояния при следующем рендеринге.
Таким образом, обновление состояния с помощью setValue(newValue) в выражении [value, setValue] = useState() осуществляется асинхронно.
Однако, функция обновления состояния может принимать коллбэк в качестве аргумента для вычисления нового состояния на основе текущего. В нашем случае мы можем использовать setCount(actualCount => actualCount + 1):
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncreaseHandler = () => {
setCount(actualCount => actualCount + 1)
setCount(actualCount => actualCount + 1)
}
return (
<>
<button onClick={doubleIncreaseHandler}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
При обновлении состояния с помощью такой функции аргумент actualCount будет содержать актуальное значение состояния.
Откройте это демо и нажмите на кнопку. Значение count увеличится до 2, как и ожидается.
Разумеется, мы всегда можем создать промежуточную переменную:
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncrease = () => {
let actualCount = count
actualCount = actualCount + 1
actualCount = actualCount + 1
setCount(actualCount)
}
return (
<>
<button onClick={this.doubleIncrease}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
let actualCount = count — это промежуточная переменная, которую можно обновлять как угодно. Эта переменная используется для обновления состояния с помощью setCount(actualCount).
2. Состояние иммутабельно (неизменяемо) и доступно только для чтения
Если вы забудете о том, что состояние обновляется при следующем рендеринге, вы можете попытаться прочитать значение сразу после его изменения. К сожалению, у вас ничего не выйдет:
function FetchUsers() {
const [users, setUsers] = useState([])
useEffect(() => {
const startFetching = async () => {
const response = await fetch('/users')
const fetchedUsers = await response.json()
setUsers(fetchedUsers)
console.log(users) // => []
console.log(fetchedUsers) // => ['John', 'Jane', 'Alice', 'Bob']
}
startFetching()
}, [])
return (
<ul>
{users.map(user => <li>{user}</li>)}
</ul>
)
}
Компонент FetchUsers отправляет запрос при монтировании — startFetching().
При получении данных setUsers(fetchedUsers) обновляет состояние. Тем не менее, изменения не происходят сразу.
Переменная users иммутабельна и доступна только для чтения. Только хук useState() может присвоить ей новое значение. Напрямую этого делать нельзя:
function FetchUsers() {
const [users, setUsers] = useState([])
useEffect(() => {
const startFetching = async () => {
const response = await fetch('/users')
const fetchedUsers = await response.json()
users = fetchedUsers // Неправильно! users доступна только для чтения
users.push(...fetchedUsers) // Неправильно! users иммутабельна
setUsers(fetchedUsers) // Правильно!
}
startFetching()
}, [])
return (
<ul>
{users.map(user => <li>{user}</li>)}
</ul>
)
}
3. Обновление состояния в классовом компоненте
Асинхронное обновление состояния характерно и для классовых компонентов.
Рассмотрим пример:
import { Component } from 'react';
class DoubleIncreaser extends Component {
state = {
count: 0
};
render() {
return (
<>
<button onClick={this.doubleIncrease}>
Double Increase
</button>
<div>Count: {this.state.count}</div>
</>
);
}
doubleIncrease = () => {
// Работает!
this.setState(({ count }) => ({
count: count + 1
}));
this.setState(({ count }) => ({
count: count + 1
}));
// Не работает!
// this.setState({ count: this.state.count + 1 });
// this.setState({ count: this.state.count + 1 });
}
}
Обратите внимание на обработчик doubleIncrease(): для обновления состояния в нем используется функция обратного вызова.
Откройте это демо и нажмите на кнопку. Значение this.state увеличится до 2.
В классовых компонентах this.state также не обновляется моментально. При вызове this.setState(newState) React откладывает обновление this.state до следующего рендеринга.
Таким образом, this.setState(newState) обновляет this.state асинхронно.
4. Заключение
Хук useState() и this.setState() (внутри классового компонента) обновляют значение переменной и состояние компонента асинхронно.
Запомните простое правило: вызов сеттера setState(newValue) хука useState() (или this.setState()) обновляет состояние не сразу, а при очередном рендеринге компонента.
Вы заметили, что React теперь достаточно импортировать только один раз (в index.js)? В компонентах этого делать больше не нужно.
Благодарю за внимание и хорошего дня.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Dmitri Pavlutin
===========Похожие новости:
- [Программирование, Управление разработкой, Развитие стартапа, Карьера в IT-индустрии, Научно-популярное] Путь CTO в небольшом стартапе (Zapier) (перевод)
- [Angular, ReactJS] Считаем code сoverage с cypress
- [JavaScript, Геоинформационные сервисы, WebGL] Особенности масштабирования WebGL-карты
- [Информационная безопасность, Программирование, Софт] Антирекорд 2020: в ПО выявили уязвимостей больше, чем в любой другой год
- [Программирование, Prolog, Искусственный интеллект, Natural Language Processing] Роль логического программирования, и стоит ли планировать его изучение на 2021-й
- [Программирование, Разработка под Android, Визуализация данных, Криптовалюты] CoinRoad: Как мы сделали приложение на базе кастомных пушей в Android
- [Программирование, Развитие стартапа, Карьера в IT-индустрии, Научно-популярное] Исповедь CTO: путь развития технического директора в стартапе (перевод)
- [Системное программирование, FPGA, Программирование микроконтроллеров, Компьютерное железо] Начинаем опыты с интерфейсом USB 3.0 через контроллер семейства FX3 фирмы Cypress
- [Разработка веб-сайтов, JavaScript, Angular, ReactJS] Что нужно знать о популярных фреймворках
- [Программирование, Java, SQL, Облачные сервисы] Контроль версий в базах данных — Сравнение Liquibase и Flyway (перевод)
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_programmirovanie (Программирование), #_reactjs, #_javascript, #_react.js, #_reactjs, #_react, #_state, #_update, #_usestate, #_setstate, #_sostojanie (состояние), #_obnovlenie (обновление), #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_javascript, #_programmirovanie (
Программирование
), #_reactjs
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:44
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Доброго времени суток, друзья! Хук useState() управляет состоянием в функциональных компонентах React. В классовых компонентах состояние хранится в this.state, а для обновления вызывается метод this.setState(). Обычно, в работе с состоянием нет ничего сложного. Тем не менее, существует один важный нюанс, связанный с его обновлением. Каким образом состояние обновляется: незамедлительно (синхронно) или отложенно (асинхронно)? Читайте дальше, чтобы узнать ответ. 1. Обноление состояния с помощью useState() Допустим у нас имеется такой функциональный компонент: import { useState } from 'react'
function DoubleIncreaser() { const [count, setCount] = useState(0) const doubleIncreaseHandler = () => { setCount(count + 1) setCount(count + 1) } return ( <> <button onClick={doubleIncreaseHandler}> Double Increase </button> <div>Count: {count}</div> </> ) } const [count, setCount] = useState(0) определяет начальное состояние компонента. count — переменная, содержащая текущее состояние, а setCount — функция обновления этого состояния. Компонент содержит кнопку Double Increase. При нажатии на эту кнопку вызывается обработчик doubleIncreaseHandler, осуществляющий два последовательных обновления count: setCount(count + 1) и затем еще раз setCount(count + 1). Каким будет состояние компонента после нажатия кнопки, 1 или 2? Откройте это демо и нажмите на кнопку. Значение count будет увеличиваться на 1 после каждого клика. Когда setCount(count + 1) обновляет состояние, значение count не изменяется сразу. Вместо этого, React планирует обновление состояния и при следующем рендеринге в выражении const [count, setCount] = useState(0) хук присваивает count новое значение. Например: если значением переменной count является 0, то вызов setCount(count + 1); setCount(count + 1) оценивается как setCount(0 + 1); setCount(0 + 1) — что приводит к 1 как значению состояния при следующем рендеринге. Таким образом, обновление состояния с помощью setValue(newValue) в выражении [value, setValue] = useState() осуществляется асинхронно. Однако, функция обновления состояния может принимать коллбэк в качестве аргумента для вычисления нового состояния на основе текущего. В нашем случае мы можем использовать setCount(actualCount => actualCount + 1): import { useState } from 'react'
function DoubleIncreaser() { const [count, setCount] = useState(0) const doubleIncreaseHandler = () => { setCount(actualCount => actualCount + 1) setCount(actualCount => actualCount + 1) } return ( <> <button onClick={doubleIncreaseHandler}> Double Increase </button> <div>Count: {count}</div> </> ) } При обновлении состояния с помощью такой функции аргумент actualCount будет содержать актуальное значение состояния. Откройте это демо и нажмите на кнопку. Значение count увеличится до 2, как и ожидается. Разумеется, мы всегда можем создать промежуточную переменную: import { useState } from 'react'
function DoubleIncreaser() { const [count, setCount] = useState(0) const doubleIncrease = () => { let actualCount = count actualCount = actualCount + 1 actualCount = actualCount + 1 setCount(actualCount) } return ( <> <button onClick={this.doubleIncrease}> Double Increase </button> <div>Count: {count}</div> </> ) } let actualCount = count — это промежуточная переменная, которую можно обновлять как угодно. Эта переменная используется для обновления состояния с помощью setCount(actualCount). 2. Состояние иммутабельно (неизменяемо) и доступно только для чтения Если вы забудете о том, что состояние обновляется при следующем рендеринге, вы можете попытаться прочитать значение сразу после его изменения. К сожалению, у вас ничего не выйдет: function FetchUsers() {
const [users, setUsers] = useState([]) useEffect(() => { const startFetching = async () => { const response = await fetch('/users') const fetchedUsers = await response.json() setUsers(fetchedUsers) console.log(users) // => [] console.log(fetchedUsers) // => ['John', 'Jane', 'Alice', 'Bob'] } startFetching() }, []) return ( <ul> {users.map(user => <li>{user}</li>)} </ul> ) } Компонент FetchUsers отправляет запрос при монтировании — startFetching(). При получении данных setUsers(fetchedUsers) обновляет состояние. Тем не менее, изменения не происходят сразу. Переменная users иммутабельна и доступна только для чтения. Только хук useState() может присвоить ей новое значение. Напрямую этого делать нельзя: function FetchUsers() {
const [users, setUsers] = useState([]) useEffect(() => { const startFetching = async () => { const response = await fetch('/users') const fetchedUsers = await response.json() users = fetchedUsers // Неправильно! users доступна только для чтения users.push(...fetchedUsers) // Неправильно! users иммутабельна setUsers(fetchedUsers) // Правильно! } startFetching() }, []) return ( <ul> {users.map(user => <li>{user}</li>)} </ul> ) } 3. Обновление состояния в классовом компоненте Асинхронное обновление состояния характерно и для классовых компонентов. Рассмотрим пример: import { Component } from 'react';
class DoubleIncreaser extends Component { state = { count: 0 }; render() { return ( <> <button onClick={this.doubleIncrease}> Double Increase </button> <div>Count: {this.state.count}</div> </> ); } doubleIncrease = () => { // Работает! this.setState(({ count }) => ({ count: count + 1 })); this.setState(({ count }) => ({ count: count + 1 })); // Не работает! // this.setState({ count: this.state.count + 1 }); // this.setState({ count: this.state.count + 1 }); } } Обратите внимание на обработчик doubleIncrease(): для обновления состояния в нем используется функция обратного вызова. Откройте это демо и нажмите на кнопку. Значение this.state увеличится до 2. В классовых компонентах this.state также не обновляется моментально. При вызове this.setState(newState) React откладывает обновление this.state до следующего рендеринга. Таким образом, this.setState(newState) обновляет this.state асинхронно. 4. Заключение Хук useState() и this.setState() (внутри классового компонента) обновляют значение переменной и состояние компонента асинхронно. Запомните простое правило: вызов сеттера setState(newValue) хука useState() (или this.setState()) обновляет состояние не сразу, а при очередном рендеринге компонента. Вы заметили, что React теперь достаточно импортировать только один раз (в index.js)? В компонентах этого делать больше не нужно. Благодарю за внимание и хорошего дня. =========== Источник: habr.com =========== =========== Автор оригинала: Dmitri Pavlutin ===========Похожие новости:
Разработка веб-сайтов ), #_javascript, #_programmirovanie ( Программирование ), #_reactjs |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:44
Часовой пояс: UTC + 5