Реагируйте useState с addEventListener - PullRequest
1 голос
/ 10 марта 2020

Может кто-нибудь объяснить мне, почему обратный вызов из addEventListener после изменения значения (по нажатию кнопки) в useState с «init» на «новое состояние» показывает значение «init», а текст в кнопке - «новое состояние»

function Test() {
    const [test, setTest] = useState("init")
    useEffect(() => {
        window.addEventListener("resize", () => console.log(test))
    }, [])

    return (
        <button style={{ marginTop: "100px" }} onClick={() => setTest("new state")}>
            {test}
        </button>
    )
}

Ответы [ 3 ]

5 голосов
/ 10 марта 2020

Добавьте test к массиву зависимостей в вашем useEffect:

useEffect(() => {
  const func = () => console.log(test);
  window.addEventListener("resize", func)
  return () => {
    window.removeEventListener("resize", func)
  }
}, [test])

Объяснение того, почему это необходимо, описано в FAQ по хукам: Почему я вижу устаревшие реквизиты или состояние внутри моей функции? :

Еще одна возможная причина, по которой вы видите устаревшие реквизиты или состояние, заключается в том, что вы используете оптимизацию «массива зависимостей», но неправильно указали все зависимости. Например, если эффект указывает [] в качестве второго аргумента, но читает someProp внутри, он будет «видеть» начальное значение someProp. Решение состоит в том, чтобы либо удалить массив зависимостей, либо исправить его.

2 голосов
/ 10 марта 2020

Пустой массив зависимостей действует как componentDidMount. Вы должны добавить тест в качестве одной из зависимостей, чтобы он снова запускался

function Test() {
    const [test, setTest] = useState("init")
    useEffect(() => {
        window.addEventListener("resize", fun)
        return () => {
        window.removeEventListener("resize", fun)
    }
    }, [test])

    return (
        <button style={{ marginTop: "100px" }} onClick={() => setTest("new state")}>
            {test}
        </button>
    )
}

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

Событие регистрируется один раз при монтировании компонента с использованием эффекта. Это та же самая функция в течение всего срока службы компонента, и она относится к устаревшему состоянию, которое было fre sh во время, когда этот eventListener был определен в первый раз.

Решением для этого является использование refs

Проверьте https://codesandbox.io/s/serverless-thunder-5vqh9, чтобы лучше понять решение

1 голос
/ 10 марта 2020

Состояние внутри эффекта, запущенного один раз, никогда не обновляется (если вы используете [])

Значение «test» внутри области вашего useEffect никогда не обновляется, так как эффект срабатывал только один раз при монтировании. Изменения состояния, которые вы делаете впоследствии, никогда не изменят это значение, если вы не запустите эффект снова, а передадите аргумент в квадратные скобки.

...