javascript - 如何从传递给监听器的回调中访问状态 Hook 值?

标签 javascript reactjs react-hooks window-resize

我有一个组件需要监听窗口调整大小,并适本地隐藏/显示边栏。 我决定为此目的创建一个自定义 Hook ,但它似乎无法正常工作。

主要问题是 mainSidebar 值始终不变,更新未正确读取。

这是钩子(Hook)本身:

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 开发检查器设备模式下切换视口(viewport)大小后,我在控制台中得到了这个输出。注意我从桌面开始,然后改为移动 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 Hook 的外部和内部之间移动 _wrapper 函数
  2. 我尝试将回调包装在 setTimeout/setImmediate 中
  3. 我尝试用一​​个函数包装状态 get (mainSidebar bool) 以检索它,该函数定义在组件中和钩子(Hook)调用之外

这些都不起作用。

我做错了什么?

最佳答案

我建议重组解决方案。首先,我会将 useResizeListener 更改为一个为您提供窗口大小的 Hook :

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

  // ...
}

关于javascript - 如何从传递给监听器的回调中访问状态 Hook 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62040275/

相关文章:

javascript - js 中的事件监听和提升

javascript - 使用 Javascript 缩进 HTML 和 CSS 代码

javascript - react 上下文不更新

javascript - React Router v6.0.0-alpha.5 历史 Prop 删除 - 在 react 上下文之外导航

javascript - 如何在 React 的溢出 div 中具有向下和向上滚动无限动画?

javascript - react | UseCallBack 内的 Prop 未在自定义 Hook 内更新

php - 显示数据库中的数据而不刷新(Javascript)

javascript - 无法获得 css 属性

javascript - Jest v22.0.6 始终将 process.env 数组转换为字符串

javascript - 事件处理程序中的 React SetState 对于模拟数据和来自 API 的数据的行为有所不同