Search code examples
reactjstypescriptreact-hooksframer-motion

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


My dimensions are not updating whenever the window is resized. In the code below you can see the window.innerHeight is updated, but the dimensions are not. I am probably missing something but I have not figured it out yet.

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

And I use the sidebar like this:

// Navbar.tsx

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

Here is an example of the logs that are returned when resizing the window:

Logs that are returned

Update 1

@sygmus1897

Code changed to this:

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

The issue remains where resizing the window does not affect the clipPath position of the circle. To illustrate the issue visually, the hamburger is supposed to be inside the green circle: Issue


Solution

  • Thanks to this thread: Framer Motion - stale custom value - changing the custom value doesn't trigger an update I found that the issue I'm having is a bug in framer-motion. To resolve this issue, add a key value to the motion component that's having issues re-rendering. This makes sure React re-renders the component.

    In my case all I had to do was this:

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