Почему начальное состояние снова и снова устанавливается в хуке useState реакции

Я создал функцию, которая прослушивает событие изменения размера, проверяет ширину окна и обновляет переменную IsMobile if(width‹=600 и IsMobile = false), а затем устанавливает для нее значение true и наоборот.

вот код:

import React, { useEffect, useState } from 'react';

export interface MechnicalLiftProps {
}

const MechnicalLift: React.SFC<MechnicalLiftProps> = () => {

    const [IsMobile, setIsMobile] = useState(true)

    const handleWindowChange = () => {

        console.log('window inner width', window.innerWidth);
        console.log('is mobile in handle', IsMobile);

        if (window.innerWidth <= 600 && IsMobile === false) {
            setIsMobile(true);
            console.log('is mobile set to true');
        }

        if (window.innerWidth > 600 && IsMobile === true) {
            setIsMobile(false);
            console.log('is mobile set to false');
        }

    }

    useEffect(() => {
        console.log('mount running');
        window.addEventListener('resize', handleWindowChange)
        handleWindowChange()
        return () => {
            window.removeEventListener('resize', handleWindowChange)
        }
    }, [])

    useEffect(() => {
        console.log('is this mobile ', IsMobile);
    }, [IsMobile])

    return (
        <div>

        </div>
    );
}

export default MechnicalLift;

мой консольный вывод:

введите здесь описание изображения

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


person ash1102    schedule 19.01.2021    source источник


Ответы (1)


Из-за пустого массива в useEffect вы настраиваете прослушиватель событий ровно один раз, при первом рендеринге. Создаваемая вами функция имеет ссылку на IsMobile из первого рендеринга, и ее значение равно true. Его значение никогда не изменится.

Если вам нужно узнать самое последнее значение состояния, вы можете использовать версию обратного вызова set state:

const handleWindowChange = () => {
  setIsMobile(prev => {
    console.log('previous value', prev);
    if (window.innerWidth <= 600 && prev === false) {
      return true;
    }
    if (window.innerWidth > 600 && prev === true) {
      return false;
    }
    return prev;
  });
});

Кстати, состояние настройки не будет перерисовываться, если значение не изменилось, поэтому вам не нужно защищаться от установки уже имеющегося значения. Другими словами, если вам не нужно ведение журнала, ваш код можно упростить до этого:

const handleWindowChange = () => {
  setIsMobile(window.innerWidth <= 600);
}
person Nicholas Tower    schedule 19.01.2021
comment
из того, что я понял, use Effect будет работать так же, как и mount, если вы оставите массив пустым, и я подумал добавить прослушиватель событий один раз, когда компонент монтируется, и удалить этот прослушиватель событий, как я делаю в компоненте размонтируется. Извините, но я не понимаю справочную часть, не могли бы вы предоставить ссылку или что-то еще для дальнейшего чтения по этому вопросу. поэтому IsMobile в функциональном компоненте не совпадает с this.state.IsMobile в компоненте на основе класса. - person ash1102; 19.01.2021
comment
В функциональных компонентах ваше состояние представлено локальными переменными. Обратите внимание, что IsMobile — это const; это никогда не изменится. Таким образом, единственный способ получить новое значение состояния — это снова выполнить рендеринг и создать новый локальный const. Поскольку вы создаете функцию обратного вызова только при первом рендеринге, эта функция обратного вызова имеет только первую локальную переменную в своем закрытии. Для получения дополнительной информации о замыканиях см. эту ссылку - person Nicholas Tower; 19.01.2021