Search code examples
reactjsuse-effect

window.visualViewport.height doenst update useEffect when a dependency


This ugly code works. Every second viewportHeight is set to the value of window.visualViewport.height

  const [viewportHeight, setViewportHeight] = React.useState(0);

  React.useEffect(() => {
    setInterval(() => {
      setViewportHeight(window.visualViewport.height);
    }, 1000);
  }, []);

However this doesn't work. viewportHeight is set on page load but not when the height changes.

  React.useEffect(() => {
    setViewportHeight(window.visualViewport.height);
  }, [window.visualViewport.height]);

Additional context: I need the page's height in state and I need the virtual keyboard's height to be subtracted from this on Mobile iOS.


Solution

  • You can only use state variables managed by React as dependencies - so a change in window.visualViewport.height will not trigger your effect.

    You can instead create a div that spans the whole screen space and use a resize observer to trigger effects when its size changes:

    import React from "react";
    import useResizeObserver from "use-resize-observer";
    
    const App = () => {
    
      const { ref, width = 0, height = 0 } = useResizeObserver();
      const [viewportHeight, setViewportHeight] = React.useState(height);
    
      React.useEffect(() => {
        setViewportHeight(window.visualViewport.height);
      }, [height]);
    
      return (
        <div ref={ref} style={{ width: "100vw", height: "100vh" }}>
          // ...
        </div>
      );
    };