[英]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
_wrapper
function between outside and inside the useEffect
hookuseEffect
挂钩的外部和内部之间移动_wrapper
functionNeither 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.