简体   繁体   English

如何将窗口调整大小事件侦听器值设置为 React State?

[英]How to set window resize event listener value to React State?

This issue is very simple but I probably overlook very little point.这个问题很简单,但我可能忽略了很少一点。 Window screen size is listening by PostLayout component. PostLayout组件正在监听窗口屏幕大小。 When window width is less than 768px, I expect that isDesktopSize is false.当窗口宽度小于 768px 时,我希望isDesktopSize为 false。 I tried everything like using arrow function in setIsDesktopSize , using text inside of true or false for state value, using callback method etc... but it's not working.我尝试了所有方法,例如在setIsDesktopSize中使用箭头函数,在 true 或 false 中使用文本作为状态值,使用回调方法等……但它不起作用。

PostLayout shared below: PostLayout分享如下:

import React, {useState,useEffect, useCallback} from 'react'
import LeftSideNavbar from './LeftSideNavbar'
import TopNavbar from './TopNavbar'

export default function PostLayout({children}) {
    const [isDesktopSize, setIsDesktopSize] = useState(true)

    let autoResize = () => {
        console.log("Desktop: " + isDesktopSize);
        console.log(window.innerWidth);
        if(window.innerWidth < 768 ){
            setIsDesktopSize(false)
        }else{
            setIsDesktopSize(true)
        }
    }

    useEffect(() => {
        window.addEventListener('resize', autoResize)
        autoResize();  
    }, [])

    return (
        <>
            <TopNavbar isDesktopSize={isDesktopSize}/>
            <main>
                <LeftSideNavbar/>
                {children}
            </main>
        </>  
    )
}

console log is shared below:控制台日志在下面共享:

Desktop: true
627

This could probably be extracted into a custom hook.这可能会被提取到自定义钩子中。 There's a few things you'd want to address:您需要解决一些问题:

  1. Right now you default the state to true , but when the component loads, that may not be correct.现在您默认状态为true ,但是当组件加载时,这可能不正确。 This is probably why you see an incorrect console log on the first execution of the effect.这可能是您在第一次执行效果时看到不正确的控制台日志的原因。 Calculating the initial state to be accurate could save you some jank/double rendering.准确计算初始状态可以为您节省一些卡顿/双重渲染。
  2. You aren't disconnecting the resize listener when the component unmounts, which could result in an error attempting to set state on the component after it has unmounted.当组件卸载时,您不会断开调整大小侦听器的连接,这可能会导致在组件卸载后尝试设置组件状态时出错。

Here's an example of a custom hook that addresses those:这是解决这些问题的自定义钩子的示例:

function testIsDesktop() {
    if (typeof window === 'undefined') {
        return true;
    }
    return window.innerWidth >= 768;
}

function useIsDesktopSize() {
    // Initialize the desktop size to an accurate value on initial state set
    const [isDesktopSize, setIsDesktopSize] = useState(testIsDesktop);

    useEffect(() => {
        if (typeof window === 'undefined') {
            return;
        }

        function autoResize() {
            setIsDesktopSize(testIsDesktop());
        }

        window.addEventListener('resize', autoResize);

        // This is likely unnecessary, as the initial state should capture
        // the size, however if a resize occurs between initial state set by
        // React and before the event listener is attached, this
        // will just make sure it captures that.
        autoResize();

        // Return a function to disconnect the event listener
        return () => window.removeEventListener('resize', autoResize);
    }, [])

    return isDesktopSize;
}

Then to use this, your other component would look like this (assuming your custom hook is just in this same file -- though it may be useful to extract it to a separate file and import it):然后要使用它,您的其他组件将如下所示(假设您的自定义挂钩只是在同一个文件中 - 尽管将其提取到单独的文件并导入它可能很有用):

import React, { useState } from 'react'
import LeftSideNavbar from './LeftSideNavbar'
import TopNavbar from './TopNavbar'

export default function PostLayout({children}) {
    const isDesktopSize = useIsDesktopSize();

    return (
        <>
            <TopNavbar isDesktopSize={isDesktopSize}/>
            <main>
                <LeftSideNavbar/>
                {children}
            </main>
        </>  
    )
}

EDIT: I modified this slightly so it should theoretically work with a server-side renderer, which will assume a desktop size.编辑:我对此稍作修改,因此理论上它应该与服务器端渲染器一起使用,该渲染器将假定桌面大小。

Try this, you are setting isDesktopSizze to 'mobile', which is === true试试这个,你将 isDesktopSizze 设置为'mobile',即 === true

 const [isDesktopSize, setIsDesktopSize] = useState(true) let autoResize = () => { console.log("Desktop: " + isDesktopSize); console.log(window.innerWidth); if(window.innerWidth < 768 ){ setIsDesktopSize(true) }else{ setIsDesktopSize(false) } }

I didn't find such a package on npm and I thought it would be nice to create one: https://www.npmjs.com/package/use-device-detect .我在 npm 上没有找到这样的包,我认为创建一个会很好: https ://www.npmjs.com/package/use-device-detect。 I think it will help someone :)我认为它会帮助某人:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM