简体   繁体   English

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

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

I have a component that needs to listen to window resize, and hide/show sidebar appropriately.我有一个组件需要听 window 调整大小,并适当地隐藏/显示侧边栏。 I decided to create a custom hook for this purpose, and it doesn't seem to work properly.我决定为此创建一个自定义挂钩,但它似乎无法正常工作。

The main problem is that the mainSidebar value is always constant, and the update is not being read properly.主要问题是mainSidebar的值始终是恒定的,并且没有正确读取更新。

This is the hook itself:这是钩子本身:

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

And this is the component using it:这是使用它的组件:

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 ...
}

Upon toggling viewport size on the Chrome dev inspector device modes, I get this output in the console.在 Chrome 开发检查器设备模式上切换视口大小后,我在控制台中得到了这个 output。 Note I started with desktop and then changed to mobile L.注意我从桌面开始,然后更改为移动 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. I tried moving the _wrapper function between outside and inside the useEffect hook我尝试在useEffect挂钩的外部和内部之间移动_wrapper function
  2. I tried wrapping the callback in a setTimeout/setImmediate我尝试将回调包装在 setTimeout/setImmediate
  3. I tried wrapping the state get (mainSidebar bool) with a function to retrieve it which is defined in the component and outside the hook call我尝试用 function 包装 state get (mainSidebar bool) 以检索它,它在组件中和钩子调用之外定义

Neither of these worked.这些都不起作用。

What am I doing wrong?我究竟做错了什么?

I would suggest restructuring the solution.我建议重组解决方案。 First I would change the useResizeListener into a hook that gives you the window size:首先,我将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;
}

Then in your HomePage component:然后在您的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.

相关问题 如何从回调之外的回调函数访问值? - How can I access a value from callback function outside of the callback? 如何在 Highcharts 事件侦听器中访问 React 钩子状态 - How to access React hook state in Highcharts event listener 无法在自定义挂钩内的回调 function 中访问 state - Can't access state in callback function inside a custom Hook 如何在 setState 回调之外访问最新的 state? - how can I access the latest state outside of the setState callback? 如何将正确的 state 值传递给 useEffect 挂钩内的回调 function? - How to pass correct state value into callback function inside useEffect hook? 如何从传递了参数的回调中返回值 - How to return a value from a callback that is passed a parameter 如何使用 useRef 钩子访问数据属性值? - How can I access data attribute value using useRef hook? 如何将密钥添加到 state 挂钩? - How can i add a key to state hook? 如何在数组依赖中正确使用 useEffect 钩子。 我从 redux 商店传递了状态,但我的组件仍然无限渲染 - How to use useEffect hook properly with array dependency. I passed state from redux store and still my component renders infinitely 如果通过钩子签入状态,如何访问自动完成的复选框和存储标题? - How can I access the Autocomplete's checked boxes and store title if checked in state via hook?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM