Javascript 如何从传递给侦听器的回调中访问状态挂钩值?

Javascript 如何从传递给侦听器的回调中访问状态挂钩值?,javascript,reactjs,react-hooks,window-resize,Javascript,Reactjs,React Hooks,Window Resize,我有一个组件需要监听窗口大小调整,并适当隐藏/显示侧边栏。 我决定为此创建一个自定义挂钩,但它似乎无法正常工作 主要问题是,mainSidebar值始终保持不变,并且没有正确读取更新 这就是钩子本身: export function useResizeListener(cb: (this: Window, e: UIEvent) => any) { const [size, setSize] = React.useState({ width: window.outerWidth,

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

主要问题是,
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 ...
}
const shouldHaveSidebar=()=>document.body.clientWidth>=屏幕大小.平板电脑
const主页:React.FunctionComponent=(道具)=>{
const[mainSidebar,toggleMainSidebar]=React.useState(shouldHaveSidebar())
useResizeListener(()=>{
调试('device width vs tablet width:',document.body.clientWidth,'>=',ScreenSizes.tablet)
调试('shouldHaveSidebar vs mainSidebar',shouldHaveSidebar(),'!==',mainSidebar)
if(shouldHaveSidebar()!==mainSidebar){
调试('设置为',shouldHaveSidebar())
ToggleMain侧边栏(shouldHaveSidebar())
}
})
返回。。。
}
在Chrome dev inspector设备模式上切换视口大小时,我在控制台中获得此输出。注:我从桌面开始,然后改为移动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
设置大小和调用回调{宽度:1680,高度:1027}
设备宽度与平板电脑宽度:1146>=800
是否应该保存侧边栏与主侧边栏正确!==假的
设置为真
设置大小和调用回调{宽度:425,高度:779}
设备宽度与平板电脑宽度:425>=800

shouldHaveSidebar vs mainSidebar false!==false/我建议重新构建解决方案。首先,我将
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;
}
然后在
主页中
组件中:

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

  // ...
}
const shouldHaveSidebar=(大小)=>size.width>=屏幕大小.平板电脑
const主页:React.FunctionComponent=(道具)=>{
常量大小=UseWindowsSize();
const Main侧边栏=应保存侧边栏(大小);
//现在,如果您想在大小更改时执行操作,您只需执行以下操作:
useffect(()=>{
//在这里执行您的操作
},[尺寸、宽度、尺寸、高度];
// ...
}

你介意发布一个演示吗?是的,给我几分钟时间。:)以下是我的观点:(基本上是Ján的方法)我无法用代码沙盒重现问题,主要是因为我无法轻松调整视口的大小。但@Ján的答案似乎比我的方法更有效。问题是,在您的案例中,它捕获了mainSidebar的初始值,并且在组件生命周期中从未更改。解决陈旧闭包的有效方法是正确设置React钩子的依赖项。