Что именно является prevState в setState функционального компонента? - PullRequest
4 голосов
/ 07 февраля 2020

Возврат (измененного) предыдущего состояния в пределах setState, полученного из ловушки useState, похоже, не изменяет состояние. Запустите следующий прямой фрагмент

function App(){
  const [state, setState] = React.useState([{x: 0}])
  function changeCount(){
    setState(prevState => {
      console.log('before', prevState[0])
      const newState = [...prevState]
      newState[0].x += 1 //the shallow copy newState could potentially change state
      console.log('after', prevState[0])//here x gets bigger as expected
      return prevState //instead of newState we return the changed prevState
    })
  }
  //checking state shows that x remained 0
  return <div className='square' onClick={changeCount}>{state[0].x}</div>
}
ReactDOM.render(<App/>, document.getElementById('root'))
.square{
  width: 100px;
  height: 100px;
  background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Нажав на квадрат, мы активируем setState. В пределах setState мы делаем поверхностную копию newState предыдущего состояния. Изменяя копию, мы меняем prevState (возможно, непреднамеренно), как подтверждает консоль. Возвращение измененного предыдущего состояния из формы setState, однако, не меняет состояние, поскольку счетчик остается 0. Если бы мы должны были вернуть newState, поведение было бы таким, как ожидалось.

Повторение этого показывает, что prevState становится больше, просто оно больше не отражает предыдущее состояние.

Почему это так? Я сделал этот минимальный пример на codepen ...

1 Ответ

4 голосов
/ 07 февраля 2020

Учтите, что присвоение объекта является просто ссылочным присвоением, а не копией

obj1 = {x:42, y:99};
obj2 = obj1;   // obj1 and obj2 both reference the same object
obj1.x += 1;   
obj2.y += 1;
console.log(obj1.x, obj1.y);
console.log(obj2.x, obj2.y);  // prints the same thing since obj1 and obj2 are the same object

В приведенном выше примере инициализация obj1 указывает на новый объект со свойствами x и y. Когда создается obj2=obj1, это не копия obj1 в obj2, а скорее obj1 и obj2 теперь ссылаются на один и тот же объект.

Следовательно, когда печатаются операторы console.log, они печатают одно и то же, потому что оба они являются значениями свойств печати из одного и того же объекта.

Аналогично, дополнительная ссылка на исходный объект делается при возникновении мелкой копии с prevState на newState.

obj = {x:42, y:99};
prevState[0] = obj;     // prevState[0] is a reference to obj.  prevState[0] and obj point to the same exact thing

newState = [...prevState];  // shallow copy, but newState[0] is an object reference.  newState[0] and prevState[0] both point to "obj"

newState[0].x += 1;         // is actually updating the original object assigned to prevState[0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...