Как я могу получить доступ к значению привязки состояния из обратного вызова, переданного слушателю? - PullRequest
3 голосов
/ 27 мая 2020

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

Основная проблема в том, что значение mainSidebar всегда постоянно и обновление не читается должным образом.

Это сам хук:

export function useResizeListener(cb: (this: Window, e: UIEvent) => any) {
    const [size, setSize] = React.useState({ width: window.outerWidth, height: window.outerHeight })

    React.useEffect(() => {
        function _wrapped(this: Window, e: UIEvent): any {
            console.debug('setting size and calling callback', { width: this.outerWidth, height: this.outerHeight })
            setSize({ width: this.outerWidth, height: this.outerHeight })
            cb.call(this, e)
        }
        window.addEventListener('resize', _wrapped)
        return () => window.removeEventListener('resize', _wrapped)
    }, [size.width, size.height])
}

И это компонент, который его использует:

const shouldHaveSidebar = () => document.body.clientWidth >= ScreenSizes.Tablet

const HomePage: React.FunctionComponent<IProps> = (props) => {
    const [mainSidebar, toggleMainSidebar] = React.useState(shouldHaveSidebar())

    useResizeListener(() => {
        console.debug('device width vs tablet width:', document.body.clientWidth, '>=', ScreenSizes.Tablet)
        console.debug('shouldHaveSidebar vs mainSidebar', shouldHaveSidebar(), '!==', mainSidebar)
        if (shouldHaveSidebar() !== mainSidebar) {
            console.debug('setting to', shouldHaveSidebar())
            toggleMainSidebar(shouldHaveSidebar())
        }
    })
    return ...
}

При переключении размера области просмотра на устройстве Chrome dev инспектора режимы, я получаю этот вывод в консоли. Примечание. Я начал с настольного компьютера, а затем перешел на мобильный L.

setting size and calling callback {width: 1680, height: 1027}
device width vs tablet width: 1146 >= 800
shouldHaveSidebar vs mainSidebar true !== false
setting to true

setting size and calling callback {width: 425, height: 779}
device width vs tablet width: 425 >= 800
shouldHaveSidebar vs mainSidebar false !== false // <--- should be: false !== true
  1. Я попытался переместить функцию _wrapper между внешним и внутренним useEffect крючком
  2. Я попытался обернуть обратный вызов в setTimeout / setImmediate
  3. Я попытался обернуть состояние get (mainSidebar bool) функцией для его извлечения, которая определена в компоненте и вне вызова ловушки

Ни то, ни другое из них сработало.

Что я делаю не так?

1 Ответ

1 голос
/ 27 мая 2020

Я бы предложил реструктурировать решение. Сначала я бы изменил useResizeListener на крючок, который дает вам размер окна:

export function useWindowSize() {
  const [size, setSize] = React.useState({ width: window.clientWidth, height: window.clientHeight });

  React.useEffect(() => {
    function handleResize(e: UIEvent) {
      setSize({ width: window.clientWidth, height: window.clientHeight });
    }

    window.addEventListener('resize', handleResize);

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
}

Затем в вашем HomePage компоненте:

const shouldHaveSidebar = (size) => size.width >= ScreenSizes.Tablet

const HomePage: React.FunctionComponent<IProps> = (props) => {
  const size = useWindowSize();
  const mainSidebar = shouldHaveSidebar(size);

  // Now if you want to perform an action when the size changes you cna simply do:
  useEffect(() => {
    // Perform your action here
  }, [size.width, size.height]);

  // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...