Как решить проблему закрытия крючка в React? - PullRequest
0 голосов
/ 09 июля 2020

import React, { useState} from "react";
import ReactDOM from "react-dom";

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

  function handleAlertClick(){
    return (setTimeout(() => {
  alert("You clicked on: " + count);
}, 3000))
  }


  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <button onClick={handleAlertClick}>Show alert</button>
    </div>
  );
}

Я просто хочу знать, работает ли это так, как я думаю, или есть лучшее объяснение!

Каждый раз, когда вызывается метод setState, состояние получает новую ссылку . Это означает, что исходное состояние не имеет нового значения, но вместо этого мы создаем новое состояние с новым значением. Когда мы нажимаем на вторую кнопку, функция обработчика событий фиксирует ссылку на исходное состояние. Даже если мы нажмем первую кнопку много раз, при отображении предупреждения будет показано значение состояния, в котором обработчик событий захватил ссылку.

Это правильно?

1 Ответ

2 голосов
/ 09 июля 2020

Причина, по которой alert показывает устаревшее значение count, заключается в том, что обратный вызов, переданный в setTimeout, ссылается на устаревшее значение count, захваченное закрытием . Обычно это называется устаревшим закрытием .

При первоначальном рендеринге анонимная функция, переданная как обратный вызов setTimeout, захватывает значение count как 0 , и когда нажимается кнопка show alert, обратный вызов ставится в очередь, но с устаревшим значением count.

В приведенном выше случае самое простое решение для отображения обновленного значения count в сообщении с предупреждением и исправления устаревшего -closure проблема заключается в использовании ref.

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

  const latestValue = useRef(count);

  const handleAlertClick = () => {
    setTimeout(() => {
      alert(`count is: ${latestValue.current}`);
    }, 3000);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button
        onClick={() => {
          setCount(prev => {
            latestValue.current = prev + 1;
            return prev + 1;
          });
        }}
      >
        Click me
      </button>
      <button onClick={handleAlertClick}>Show alert</button>
    </div>
  );
}

Рабочая демонстрация в codeandbox

Работа хуков в значительной степени зависит от замыканий, поэтому очень вероятно, что вы можете столкнуться с проблемами, касающимися устаревших закрытий . Вот хорошая статья о том, как устаревшие замыкания создают проблемы при использовании перехватчиков реакции, и демонстрирует, как исправить некоторые проблемы в некоторых ситуациях.

...