React 调整大小事件侦听器未使用 useCallBack 更新状态

问题描述 投票:0回答:1

我不知道我是否没有理解 useCallBack 的用途,或者我是否做错了什么。

我有一个钩子来确定我是在台式机、平板电脑还是移动设备上,它会监听屏幕的宽度。这很好用。

现在我有一个组件需要计算某些东西的高度,我只需要在移动设备中执行此操作,并且我正在监听窗口大小调整,以防某些文本中断和高度增加。

但是在我的组件中的

handleWindowSizeChange
函数中,isDesktop 始终具有初始值。甚至使用
useCallBack
钩子。

这是我的代码:

const handleWindowSizeChange = useCallback(() => {
    console.log(isDesktop)  // if I start in desktop it's always true, if I start in mobile it's always false.
}, [isDesktop]);

useEffect(() => {
   console.log(isDesktop) //This triggers when you hit the breakpoint with the correct value
}, [isDesktop]);

useEffect(() => {
  if (!loaded) return;
  handleWindowSizeChange();
  window.addEventListener('resize', handleWindowSizeChange);
        
  return () => {
     window.removeEventListener('resize', handleWindowSizeChange);
  }
}, [loaded]);

这是我的钩子(丑陋但有效):

'use client'
import { useState, useEffect } from 'react';
import { throttle } from './utils';

export default function useDeviceDetect() {
    const [isMobile, setMobile] = useState(false);
    const [isTablet, setTablet] = useState(false);
    const [isDesktop, setDesktop] = useState(false);
    const [loaded, setLoaded] = useState(false);

    const breakpointSmall = 480;
    const breakpointMedium = 960;
    const breakpointLarge = 1280;
    const breakpointXLarge = 1680;

    function handleWindowSizeChange() {
        if (window.screen.width < breakpointSmall) {
            setMobile(true);
            setTablet(false);
            setDesktop(false);
        }
        if (window.screen.width >= breakpointSmall && window.screen.width < breakpointMedium) {
            setMobile(false);
            setTablet(true);
            setDesktop(false);
        }

        if (window.screen.width >= breakpointMedium && window.screen.width < breakpointLarge) {
            setMobile(false);
            setTablet(false);
            setDesktop(true);
        }

        if (window.screen.width >= breakpointLarge && window.screen.width < breakpointXLarge) {
            setMobile(false);
            setTablet(false);
            setDesktop(true);
        }

        if (window.screen.width >= breakpointXLarge) {
            setMobile(false);
            setTablet(false);
            setDesktop(true);
        }

        setLoaded(true);
    }

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

    return { isMobile, isTablet, isDesktop, loaded };
}

如果我理解正确,

useCallBack
会缓存该函数并在依赖项发生变化时重建它。 我认为这个钩子是为了“修复错误”,例如在
setInterval
中状态没有更新。

我做错了什么还是我没有理解这个钩子?

javascript reactjs next.js
1个回答
0
投票

使用

window.innerWidth
代替
window.screen.width

"use client"
import { useState, useEffect, useCallback } from "react"

export default function useDeviceDetect() {
    const [device, setDevice] = useState({
        isMobile: false,
        isTablet: false,
        isDesktop: false,
        loaded: false,
    })

    const breakpoints = { small: 480, medium: 960, large: 1280, xLarge: 1680 }

    const handleWindowSizeChange = useCallback(() => {
        // Use window.innerWidth (not window.screen.width)
        const width = window.innerWidth
        setDevice({
            isMobile: width < breakpoints.small,
            isTablet: width >= breakpoints.small && width < breakpoints.medium,
            isDesktop: width >= breakpoints.medium,
            loaded: true,
        })
    }, [breakpoints.medium, breakpoints.small])

    useEffect(() => {
        handleWindowSizeChange()
        window.addEventListener("resize", handleWindowSizeChange)
        return () => window.removeEventListener("resize", handleWindowSizeChange)
    }, [handleWindowSizeChange])

    return device
}
© www.soinside.com 2019 - 2024. All rights reserved.