【问题标题】:How to set window resize event listener value to React State?如何将窗口调整大小事件侦听器值设置为 React State?
【发布时间】:2021-06-17 12:12:21
【问题描述】:

这个问题很简单但是我可能忽略了很少一点。 PostLayout 组件正在监听窗口屏幕大小。当窗口宽度小于 768px 时,我预计 isDesktopSize 为 false。我尝试了所有方法,例如在setIsDesktopSize 中使用箭头函数、在 true 或 false 中使用文本作为状态值、使用回调方法等……但它不起作用。

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

控制台日志共享如下:

Desktop: true
627

【问题讨论】:

    标签: reactjs next.js


    【解决方案1】:

    这可能会被提取到自定义挂钩中。您想解决一些问题:

    1. 现在您默认状态为true,但是当组件加载时,这可能不正确。这可能是您在第一次执行效果时看到不正确的控制台日志的原因。准确计算初始状态可以为您节省一些卡顿/双重渲染。
    2. 当组件卸载时,您没有断开调整大小侦听器的连接,这可能会导致在组件卸载后尝试设置组件状态时出错。

    以下是解决这些问题的自定义挂钩示例:

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

    然后要使用它,您的其他组件将如下所示(假设您的自定义钩子就在同一个文件中 - 尽管将其提取到单独的文件并导入它可能很有用):

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

    编辑:我对此稍作修改,因此理论上它应该与服务器端渲染器一起使用,该渲染器将假定桌面大小。

    【讨论】:

    • 感谢您对 Marc Baumbach 的回复。当我尝试您的建议时,我不断发现“未定义窗口”错误。我研究了这个错误。这个link 可以是解决方案,但对我不起作用。其实 GoonGamja 的问题和我一样。最后,我无法通过这个编译错误。
    • @swim 此代码是否也在服务器端渲染器上运行?此代码假定它只在浏览器上运行。 window 在浏览器中始终可用。
    • 我修改了代码以检查是否定义了window。如果不是,它基本上不会运行并假定它是桌面大小,尽管可能没有明确正确的解决方案。
    • 现在正在设置桌面大小值 :) 这个问题的目的是使用 isDesktopSize 值添加响应属性。当“isDesktopSize”值为假时,我的顶部导航栏组件中的某些元素应该消失。我收到类似“类名不匹配”的警告。服务器:TopNavbar d-flex,客户端:“TopNavbar d-none”。因此,应用程序从服务器端做出决定。这些问题,例如窗口,由于 ssr 应用程序导致的类属性不匹配,我可以迁移普通的 react 项目或客户端项目。
    • 我了解到没有ssr的动态导入。这种导入风格是我 unmacthing 类属性的解决方案。类属性的初始值设置正确,因为 TopNavbar 组件正在导入客户端。
    【解决方案2】:

    试试这个,你将 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)
            }
        }

    【讨论】:

    • 感谢您的快速回复,但我更新了我的问题并更改了这些行。您可以删除答案,但谢谢...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多