Объяснение: получить предыдущее состояние

#javascript #reactjs #user-interface #react-hooks #state

#javascript #reactjs #пользовательский интерфейс #реагирующие крючки #состояние

Вопрос:

Я читаю документацию React, и есть тема, которую я не очень хорошо понял:

https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state

 function Counter() {
  const [count, setCount] = useState(0);

  const prevCountRef = useRef();
  useEffect(() => {
    prevCountRef.current = count;
  });
  const prevCount = prevCountRef.current;

  return <h1>Now: {count}, before: {prevCount}</h1>;
}
 

ДЕМОНСТРАЦИЯ:

https://codesandbox.io/s/get-previous-state-ref—hook-faq-w0f3k?file=/src/App.js

Я хотел бы получить лучшее объяснение по этому поводу. Вид, как это работает?. Спасибо

Ответ №1:

Здесь три части. Состояние, ссылка и эффект.

Состояние — это значение, которое запоминается между отображениями, и оно повторно отображает его компонент при изменении.

Ссылка (или ссылка) — это значение, которое сохраняется между рендерами, как это делает state, но в отличие от state оно не отслеживается на предмет каких-либо изменений и может быть изменено свободно. Изменения ссылок никогда не вызывают рендеринга.

Эффект — это просто функция, которая запускается после рендеринга или после того, как рендеринг в одной из его зависимостей изменился с момента предыдущего рендеринга.


Итак, собрав все это вместе, вот что получается:

 const [count, setCount] = useState(0);
 

Здесь объявляется состояние. Вызов setCount с новым значением приведет к рендерингу компонента, и когда это произойдет, count он будет иметь значение, которое было установлено.

 const prevCountRef = useRef();
 

Затем объявите ссылку. При этом будет содержаться ссылка на предыдущее значение счетчика. Прямо сейчас у него нет значения ( undefined ), что имеет смысл, учитывая, что при первом отображении компонента предыдущего значения нет.

 useEffect(() => {
  prevCountRef.current = count;
});
 

Теперь объявите эффект, который выполняется после каждого рендеринга (вы можете сказать это, потому что он не имеет зависимостей (будет вторым аргументом useEffect() ). Когда это выполняется, оно устанавливает текущее значение prevCountRef равным любому значению.


Итак, при первом рендеринге в псевдокоде:

 // render starts

count // 0
prevCountRef.current // undefined

// render finishes

effect runs {
  prevCountRef.current is set to 0
}
 

Таким образом , когда происходит рендеринг , count состояние равно 0 , а предыдущее значение счетчика undefined равно .


Второй рендеринг:

 setCount(1) // triggers the second render

// second render starts

count // 1
prevCount.current // 0

// second render finishes

effect runs {
  prevCount.current is set to 1  
}
 

Итак, как вы можете видеть, во время рендеринга у вас всегда есть текущее значение как состояние as, а предыдущее значение — как ссылка. Это работает, потому что эффект, который устанавливает значение refs, всегда выполняется после завершения рендеринга, что позволяет ему быть таким, каким было предыдущее значение.

Комментарии:

1. Большое тебе спасибо, Алекс. Есть одна фраза, которую я забыл. «useEffect всегда запускается после рендеринга» . Эта фраза — то, что я искал.. Спасибо

Ответ №2:

Вы можете использовать componentDidUpdate для получения предыдущих реквизитов и состояния. Когда вы расширяете React.Компонент, он будет вызывать componentDidUpdate после каждого рендеринга. Вы определяете функцию, и React передаст вам предыдущие реквизиты и предыдущее состояние.

https://reactjs.org/docs/react-component.html#componentdidupdate

Комментарии:

1. Привет @djones. Я прочитал часть документа. Но, в моей ссылке документации о часто задаваемых вопросах about hook. Я не понял, как prevCountRef получить предыдущее состояние с помощью useRef. Мне просто нужно объяснение. Это не вариант использования.

2. componentDidUpdate предназначен для компонентов класса и не является частью API функциональных компонентов. Так что на самом деле это здесь неприменимо.

Ответ №3:

useEffect вызывается сразу после рендеринга компонента. Первый раз, когда компонент отображает prevCount undefined , потому что useEffect еще не был вызван.

предварительная визуализация: 1) value: 0, prevCount: undefined

пост-рендеринг: вызывается useEffect:

2) value: 0, prevCount: 0 useRef не вызывайте новый рендеринг, поэтому компонент не обновляется. refCount будет показан как неопределенный.

при изменении значения счетчика компонент получает повторную визуализацию:

предварительная визуализация:

3) value: 1, prevCount: 0 useEffect еще не вызван.

пост-рендеринг:

4) value: 1, prevCount: 1 Вызывается useEffect, prevCount увеличивается, но компонент не обновляется, поэтому prevCount будет отображаться значение = 0;

Комментарии:

1. Спасибо @antonio! Превосходно обобщенное объяснение!