簡體   English   中英

如何從傳遞給偵聽器的回調中訪問 state 掛鈎值?

[英]How can I access a state hook value from a callback passed to a listener?

我有一個組件需要聽 window 調整大小,並適當地隱藏/顯示側邊欄。 我決定為此創建一個自定義掛鈎,但它似乎無法正常工作。

主要問題是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 開發檢查器設備模式上切換視口大小后,我在控制台中得到了這個 output。 注意我從桌面開始,然后更改為移動 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. 我嘗試在useEffect掛鈎的外部和內部之間移動_wrapper function
  2. 我嘗試將回調包裝在 setTimeout/setImmediate
  3. 我嘗試用 function 包裝 state get (mainSidebar bool) 以檢索它,它在組件中和鈎子調用之外定義

這些都不起作用。

我究竟做錯了什么?

我建議重組解決方案。 首先,我將useResizeListener更改為一個鈎子,為您提供 window 大小:

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]);

  // ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM