React + useState () + previousState

Sep 11 2020

Я совсем недавно отреагировал, и у меня проблемы с пониманием хука 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?

Вы понимаете мое замешательство? Я не уверен, как мне это оформить по-другому ...

Большое спасибо за Вашу помощь.

Ответы

6 devserkan Sep 11 2020 at 19:15

Прежде всего, вы можете увидеть официальное объяснение здесь .

В этом случае я каким-то образом обращаюсь к предыдущему значению счетчика.

Вы каким-то образом не получаете доступ к предыдущему значению счетчика. Если вы используете функциональное обновление и передаете сеттеру функцию обратного вызова, он возвращает вам предыдущее состояние, и вы используете это значение в своей функции обратного вызова.

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, она берет ее, а затем запускает ее в нашем состоянии и возвращает значение обратно.

1 VietDinh Sep 11 2020 at 19:10

Вот мое мнение, как я понимаю:

В этом случае я каким-то образом обращаюсь к предыдущему значению счета. -> setCount проверит параметр, если параметр является обратным вызовом, он вызовет этот обратный вызов и передаст предыдущее состояние для параметра. Результатом обратного звонка будет следующее состояние.

setCount теперь ожидает функцию -> да, функция обрабатывает вашу логику и возвращает следующее состояние.

setCount теперь запускается асинхронно -> эта функция является синхронной, но после возврата результата. Ловушка для setCount отправит событие для обновления следующего состояния

Откуда эта функция? -> вы можете делать что угодно в функции, пока param будет текущим состоянием и вернет следующее состояние.

Откуда приходит prevCount? -> будет передан при вызове setCount (получен из текущего состояния).

Когда я запускаю это, что помещается в prevCount? -> текущее состояние setCount.

=> Пример того, как передать значение или обратный вызов setCount здесь: хук useState, функция setState. Доступ к предыдущему значению состояния