最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - useEffect hook not firing on orientation change - Stack Overflow

programmeradmin2浏览0评论

I am trying to change the height of a container, when in mobile landscape mode only. I am playing around in the developer tools to swap the orientation of a mobile device but it only works on the first render. I am new to react hooks so not sure if I am implementing it right.

The idea is that I am testing that once in landscape, if it's on mobile the height should be less than 450px (which is the check I am doing for the if statement)

Could someone point me in the right direction, please?

Thanks!

const bikeImageHeight = () => {
    const windowViewportHeight = window.innerHeight;
    const isLandscape = window.orientation === 90 || window.orientation === -90;
    let bikeImgHeight = 0;

    if (windowViewportHeight <= 450 && isLandscape) {
      bikeImgHeight = windowViewportHeight - 50;
    }

    return bikeImgHeight;
  };

  useEffect(() => {
    bikeImageHeight();

    window.addEventListener("resize", bikeImageHeight);

    return () => {
      window.removeEventListener("resize", bikeImageHeight);
    };
  }, []);

I am trying to change the height of a container, when in mobile landscape mode only. I am playing around in the developer tools to swap the orientation of a mobile device but it only works on the first render. I am new to react hooks so not sure if I am implementing it right.

The idea is that I am testing that once in landscape, if it's on mobile the height should be less than 450px (which is the check I am doing for the if statement)

Could someone point me in the right direction, please?

Thanks!

const bikeImageHeight = () => {
    const windowViewportHeight = window.innerHeight;
    const isLandscape = window.orientation === 90 || window.orientation === -90;
    let bikeImgHeight = 0;

    if (windowViewportHeight <= 450 && isLandscape) {
      bikeImgHeight = windowViewportHeight - 50;
    }

    return bikeImgHeight;
  };

  useEffect(() => {
    bikeImageHeight();

    window.addEventListener("resize", bikeImageHeight);

    return () => {
      window.removeEventListener("resize", bikeImageHeight);
    };
  }, []);

Share Improve this question asked Oct 15, 2019 at 15:26 markmark 2453 silver badges14 bronze badges 0
Add a ment  | 

3 Answers 3

Reset to default 7

The useEffect hook is not expected to fire on orientation change. It defines a callback that will fire when the ponent re-renders. The question then is how to trigger a re-render when the screen orientation changes. A re-render occurs when there are changes to a ponents props or state.

Lets make use of another related stackoverflow answer to build a useWindowDimensions hook. This allows us to hook into the windows size as ponent state so any changes will cause a re-render.

useWindowDimensions.js

import { useState, useEffect } from 'react';

function getWindowDimensions() {
  const { innerWidth: width, innerHeight: height } = window;
  return {
    width,
    height
  };
}

export default function useWindowDimensions() {
  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }

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

  return windowDimensions;
}

You can then use that hook in your ponent. Something like:

BikeImage.js

import React from 'react'
import useWindowDimensions from './useWindowDimensions'

export default () => {
  const windowDimensions = useWindowDimensions();

  // Define these helper functions as you like
  const width = getImageWidth(windowDimensions.width)
  const height = getImageHeight(windowDimensions.height)

  // AppImage is a ponent defined elsewhere which takes 
  // at least width, height and src props
  return <AppImage  width={width} height={height} src="..." .../>
}

Here is a custom hook that fires on orientation change,

import React, {useState, useEffect} from 'react';

// Example usage
export default () => {
  const orientation = useScreenOrientation();
  return <p>{orientation}</p>;
}

function useScreenOrientation() {
  const [orientation, setOrientation] = useState(window.screen.orientation.type);

  useEffect(() => {
    const handleOrientationChange= () => setOrientation(window.screen.orientation.type);
    window.addEventListener('orientationchange', handleOrientationChange);
    return () => window.removeEventListener('orientationchange', handleOrientationChange);
  }, []);

  return orientation;
}

Hope this takes you to the right direction.

You need to trigger a re-render, which can be done by setting state inside of your bikeImageHeight.

  const [viewSize, setViewSize] = useState(0)


    const bikeImageHeight = () => {
        const windowViewportHeight = window.innerHeight;
        const isLandscape = window.orientation === 90 || window.orientation === -90;
        let bikeImgHeight = 0;

        if (windowViewportHeight <= 450 && isLandscape) {
          bikeImgHeight = windowViewportHeight - 50;
        }
        setViewSize(bikeImgHeight)
        return bikeImgHeight;
  };

And per the ments conversation, here's how you'd use debounce:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};


const YourComponent = () => {

  const bikeImageHeight = () => {
    const windowViewportHeight = window.innerHeight;
    const isLandscape = window.orientation === 90 || window.orientation === -90;
    let bikeImgHeight = 0;

    if (windowViewportHeight <= 450 && isLandscape) {
      bikeImgHeight = windowViewportHeight - 50;
    }
    setViewSize(bikeImgHeight)
    return bikeImgHeight;
  };


  const debouncedBikeHeight = debounce(bikeImageHeight, 200)

  useEffect(() => {
    bikeImageHeight();

    window.addEventListener("resize", debouncedBikeHeight);

    return () => {
      window.removeEventListener("resize", debouncedBikeHeight);
    };
  }, []);

  return <div>some jsx</div>

}

Example debounce taken from here: https://davidwalsh.name/javascript-debounce-function

发布评论

评论列表(0)

  1. 暂无评论