React + useState () + previousState
Я совсем недавно отреагировал, и у меня проблемы с пониманием хука useState - или, точнее, аспекта previousState .
Обычный перехватчик useState и, вероятно, наиболее распространенный пример, выглядит так:
import React, { useState} from 'react';
export default function CounterHooks({ initialCount }){
const [count, setCount] = useState(initialCount);
return (
<div>
<button onClick={() => setCount(count -1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
На данный момент я понимаю следующее:
- Я вызываю функцию useState () / Hook? и передать аргумент начального состояния (initialCount)
- Я возвращаю массив, который я немедленно разрушаю на счетчик переменных и setCount (который является функцией)
- С setCount () я могу обновить состояние и, следовательно, переменную count
Думаю, пока все хорошо ...;)
Иногда я вижу тот же пример счетчика с prevState (prevCount), которого я не понимаю:
<button onClick={() => setCount(prevCount => prevCount -1)}>-</button>
Что здесь происходит? Эту часть я не понимаю. Мои мысли на данный момент:
- В этом случае я каким-то образом обращаюсь к предыдущему значению счетчика.
- setCount теперь ожидает функцию
- setCount теперь запускается асинхронно
- Откуда эта функция?
- Откуда приходит prevCount?
- Когда я запускаю это, что помещается в prevCount?
Вы понимаете мое замешательство? Я не уверен, как мне это оформить по-другому ...
Большое спасибо за Вашу помощь.
Ответы
Прежде всего, вы можете увидеть официальное объяснение здесь .
В этом случае я каким-то образом обращаюсь к предыдущему значению счетчика.
Вы каким-то образом не получаете доступ к предыдущему значению счетчика. Если вы используете функциональное обновление и передаете сеттеру функцию обратного вызова, он возвращает вам предыдущее состояние, и вы используете это значение в своей функции обратного вызова.
setCount теперь ожидает функцию
Поскольку вы предоставляете функцию, он может ее использовать.
setCount теперь запускается асинхронно
Вообще-то, нет. Это не асинхронная функция. Он просто предоставляет предыдущее состояние, и вы его используете. Установщики состояния не являются асинхронными, обновление состояния есть.
Откуда эта функция?
Откуда приходит prevCount?
Уже ответил.
Когда я запускаю это, что помещается в prevCount?
Вы указываете то, что хотите установить в новом состоянии. В вашем примере вы хотите увеличить countна 1, поэтому вы предоставляете+ 1
Вот наивное объяснение этой логике. Просто наивный. Я добавляю это, чтобы проиллюстрировать логику обратного вызова, это не связано с ReactsetState.
let state = 5;
function setState(val) {
if (typeof val === "function") {
return val(state);
}
return val;
}
const stateWithFunctionalUpdate = setState(prev => prev + 1);
const stateWithNormalUpdate = setState(9);
console.log(stateWithFunctionalUpdate);
console.log(stateWithNormalUpdate);
Возможно, этот пример подойдет для имитации логики настройки состояния React. Опять же, просто наивный подход.
let state = 5;
function setState(val) {
if (typeof val === "function") {
state = val(state);
} else {
state = val;
}
}
setState(9);
setState(prev => prev + 1);
console.log("state", state);
Давайте посмотрим на реальной реализации в useState(без типизации):
export function useState(initialState) {
return useReducer(
basicStateReducer,
// useReducer has a special case to support lazy useState initializers
initialState
);
}
Ну, его просто используют useReducerза шторами. Он устанавливает начальное состояние и использует basicStateReducer, который:
function basicStateReducer(state, action) {
return typeof action === "function" ? action(state) : action;
}
Как и наш наивный подход, он ищет тип actionи ведет себя в соответствии с ним. Наконец, вот что useReducer возвращается :
return [workInProgressHook.memoizedState, dispatch];
Итак, в конце дня, если мы предоставляем функцию для useState, она берет ее, а затем запускает ее в нашем состоянии и возвращает значение обратно.
Вот мое мнение, как я понимаю:
В этом случае я каким-то образом обращаюсь к предыдущему значению счета. -> setCount проверит параметр, если параметр является обратным вызовом, он вызовет этот обратный вызов и передаст предыдущее состояние для параметра. Результатом обратного звонка будет следующее состояние.
setCount теперь ожидает функцию -> да, функция обрабатывает вашу логику и возвращает следующее состояние.
setCount теперь запускается асинхронно -> эта функция является синхронной, но после возврата результата. Ловушка для setCount отправит событие для обновления следующего состояния
Откуда эта функция? -> вы можете делать что угодно в функции, пока param будет текущим состоянием и вернет следующее состояние.
Откуда приходит prevCount? -> будет передан при вызове setCount (получен из текущего состояния).
Когда я запускаю это, что помещается в prevCount? -> текущее состояние setCount.
=> Пример того, как передать значение или обратный вызов setCount здесь: хук useState, функция setState. Доступ к предыдущему значению состояния