为什么在使用 React Hooks 时我的尺寸没有在调整大小时更新

Why are my dimensions not updating on resize when using React Hooks

每当 window 调整大小时,我的尺寸都不会更新。在下面的代码中,您可以看到 window.innerHeight 已更新,但尺寸没有。我可能遗漏了一些东西,但我还没有弄明白。

// Navbar.components.ts:

export const sidebar = () => {
    let height;
    let width;

    if (typeof window !== `undefined`) {
        height = window.innerHeight
        width = window.innerWidth
    }

    const [dimensions, setDimensions] = useState({
        windowHeight: height,
        windowWidth: width,
    })

    useEffect(() => {
        const debouncedHandleResize = debounce(function handleResize() {
            setDimensions({
                windowHeight: window.innerHeight,
                windowWidth: window.innerWidth,
            });
            // Logging window.innerHeight gives the current height,
            // Logging dimensions.windowHeight gives the initial height
            console.log(window.innerHeight, " . ", dimensions.windowHeight)
        }, 100);

        window.addEventListener(`resize`, debouncedHandleResize)
        return () => window.removeEventListener('resize', debouncedHandleResize)

    }, [])

    return {
        open: () => ({
            clipPath: `circle(${dimensions.windowHeight * 2 + 200}px at 40px 40px)`,
            transition: {
                type: "spring",
                stiffness: 20,
                restDelta: 2
            }
        }),
        closed: () => ({
            clipPath: `circle(30px at ${300 - 40}px ${dimensions.windowHeight - 45}px)`,
            transition: {
                delay: 0.2,
                type: "spring",
                stiffness: 400,
                damping: 40
            }
        })
    }
}

我这样使用侧边栏:

// Navbar.tsx

const Navbar: React.FC<NavbarProps> = () => {
  ...
  
  return {
      ...
      <MobileNavBackground variants={sidebar()} />
      ...
  }
}

这是调整 window 大小时返回的日志示例:

更新 1

@sygmus1897

代码更改为:

// Navbar.tsx: 

const Navbar: React.FC<NavbarProps> = () => {

  const [windowWidth, windowHeight] = getDimensions();
  useEffect(() => {
  }, [windowWidth, windowHeight])

  return (
     ...
     <MobileNavWrapper
        initial={false}
        animate={menuIsOpen ? "open" : "closed"}
        custom={height}
        ref={ref}
        menuIsOpen={menuIsOpen}
      >
        <MobileNavBackground variants={sidebar} custom={windowHeight} />
        <MobileNav menuIsOpen={menuIsOpen} toggleMenu={toggleMenu} />
        <MenuToggle toggle={() => toggleMenu()} />
      </MobileNavWrapper>
   )
}
// getDimensions()
export const getDimensions = () => {
    const [dimension, setDimension] = useState([window.innerWidth, window.innerHeight]);

    useEffect(() => {
        window.addEventListener("resize", () => {
            setDimension([window.innerWidth, window.innerHeight])
        });
        return () => {
            window.removeEventListener("resize", () => {
                setDimension([window.innerWidth, window.innerHeight])
            })
        }
    }, []);
    
    return dimension;

};
// Navbar.components.ts

export const sidebar = {
    open: (height) => ({
        clipPath: `circle(${height + 200}px at 40px 40px)`,
        transition: {
            type: "spring",
            stiffness: 20,
            restDelta: 2
        }
    }),
    closed: (height) => ({
        clipPath: `circle(30px at ${300 - 60}px ${height - 65}px)`,
        transition: {
            delay: 0.2,
            type: "spring",
            stiffness: 400,
            damping: 40
        }
    })
}

问题仍然存在,调整 window 的大小不会影响圆的 clipPath 位置。为了直观地说明问题,汉堡包应该在绿色圆圈内:

您可以创建自定义挂钩来监听 window 调整大小。

您可以根据您的要求修改此 link 的解决方案

通过使用 useState 而不是 ref,在调整大小时更新它并将值返回到您的主要组件

这是一个例子:

export default function useWindowResize() {
    const [dimension, setDimension] = useState([0, 0]);

    useEffect(() => {
        window.addEventListener("resize", () => {
            setDimension([window.innerWidth, window.innerHeight])
        });
        return () => {
            window.removeEventListener("resize", () => {
                setDimension([window.innerWidth, window.innerHeight])
            })
        }
    }, []);
    
    return dimension;
}

在你的主要组件中使用它:

const MainComponent = () => {
    const [width, height] = useWindowResize();
    useEffect(()=>{
        // your operations
    }, [width, height])
}

每次更改尺寸时,您的组件都会更新。你会得到更新后的宽度和高度

编辑:

Framer-motion 提供了一种动态设置变量属性的方法(详细指南请参考Dynamically Update Variant):-

// Navbar.tsx: 

const Navbar: React.FC<NavbarProps> = () => {
  return (
     ...
     <MobileNavWrapper
        initial={false}
        custom={window.innerWidth} // custom={window.innerHeight} if variable depends on Height
        animate={menuIsOpen ? "open" : "closed"}
        custom={height}
        ref={ref}
        menuIsOpen={menuIsOpen}
      >
        <MobileNavBackground variants={sidebar} />
        <MobileNav menuIsOpen={menuIsOpen} toggleMenu={toggleMenu} />
        <MenuToggle toggle={() => toggleMenu()} />
      </MobileNavWrapper>
   )
}
// Navbar.components.ts

export const sidebar = {
    open: (width) => ({ 
        clipPath: `circle(${width+ 200}px at 40px 40px)`,
        transition: {
            type: "spring",
            stiffness: 20,
            restDelta: 2
        }
    }),
    closed: (width) => ({
        clipPath: `circle(30px at ${300 - 60}px ${width- 65}px)`,
        transition: {
            delay: 0.2,
            type: "spring",
            stiffness: 400,
            damping: 40
        }
    })
}

感谢这个帖子: 我发现我遇到的问题是 framer-motion 中的错误。要解决此问题,请向重新渲染出现问题的运动组件添加一个键值。这确保 React 重新渲染组件。

就我而言,我所要做的就是:

<MobileNavBackground variants={sidebar} custom={windowHeight} key={key} />