【问题标题】:How to detect if screen size has changed to mobile in React?如何在 React 中检测屏幕尺寸是否已更改为移动设备?
【发布时间】:2017-11-12 18:51:18
【问题描述】:

我正在使用 React 开发一个 Web 应用程序,需要检测屏幕尺寸何时进入移动断点以更改状态。

具体来说,当用户进入移动模式时,我需要折叠我的 sidenav,并通过存储在组件内的状态中的布尔值进行控制。

【问题讨论】:

    标签: reactjs responsive


    【解决方案1】:

    我所做的是在组件挂载后添加一个事件监听器:

    componentDidMount() {
        window.addEventListener("resize", this.resize.bind(this));
        this.resize();
    }
    
    resize() {
        this.setState({hideNav: window.innerWidth <= 760});
    }
    
    componentWillUnmount() {
        window.removeEventListener("resize", this.resize.bind(this));
    }
    

    编辑: 为了保存状态更新,我稍微改变了“resize”,只在窗口宽度发生变化时才更新。

    resize() {
        let currentHideNav = (window.innerWidth <= 760);
        if (currentHideNav !== this.state.hideNav) {
            this.setState({hideNav: currentHideNav});
        }
    }
    

    更新:是时候使用钩子了! 如果您的组件是功能性的,并且您使用挂钩 - 那么您可以使用来自 react-responsive 包的 useMediaQuery 挂钩。

    import { useMediaQuery } from 'react-responsive';
    
    ...
    
    const isMobile = useMediaQuery({ query: `(max-width: 760px)` });
    

    使用此钩子后,“isMobile”将在屏幕调整大小时更新,并重新渲染组件。好多了!

    【讨论】:

    • 您需要去抖动或限制该事件侦听器。您将找到here 的示例。
    【解决方案2】:

    这与@Ben Cohen answer 相同,但在将您的函数附加到 eventListner 后,还要在 componentWillUnmount

    上将其删除
    constructor() {
      super();
      this.state = { screenWidth: null };
      this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
    }
    
    componentDidMount() {
        window.addEventListener("resize", this.updateWindowDimensions());
    }
    
    componentWillUnmount() {
        window.removeEventListener("resize", this.updateWindowDimensions)
    }
    
    updateWindowDimensions() {
       this.setState({ screenWidth: window.innerWidth });
    }
    

    【讨论】:

    • 这是正确答案,应该这样标记。 (它也应该被去抖动或节流,正如 ivarni 对上述答案的评论。)
    • 在调用 addEventListener 时,它应该只传递 this.updateWindowDimensions 引用而不是调用它。
    【解决方案3】:

    在 React(16.8.0+) 中使用 hooks 指的是: https://stackoverflow.com/a/36862446/1075499

    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;
    }
    

    【讨论】:

    【解决方案4】:
    const [isMobile, setIsMobile] = useState(false)
     
    //choose the screen size 
    const handleResize = () => {
      if (window.innerWidth < 720) {
          setIsMobile(true)
      } else {
          setIsMobile(false)
      }
    }
    
    // create an event listener
    useEffect(() => {
      window.addEventListener("resize", handleResize)
    })
    
    // finally you can render components conditionally if isMobile is True or False 
    

    【讨论】:

      【解决方案5】:

      嘿,我刚刚为这个问题发布了一个 npm 包。 看看https://www.npmjs.com/package/react-getscreen

      import React, { Component } from 'react';
      import {withGetScreen} from 'react-getscreen'
      
      class Test extends Component {
        render() {
          if (this.props.isMobile()) return <div>Mobile</div>;
          if (this.props.isTablet()) return <div>Tablet</div>;
          return <div>Desktop</div>;
        }
      }
      
      export default withGetScreen(Test);
      
      //or you may set your own breakpoints by providing an options object
      
      const options = {mobileLimit: 500, tabletLimit: 800}
      export default withGetScreen(Test, options);
      

      【讨论】:

      • 如果你问我,浏览器应该更容易获得物理屏幕尺寸而不仅仅是分辨率,因为像素密度变化很大......
      • 根据我的经验,根据屏幕尺寸布置的组件的可重用性较低,因为例如,如果您将它们放在 2 x 2 网格中,它们将呈现为整个屏幕而不是四分之一。
      • 嗯,像这样的插件,只能用在容器组件之类的东西上
      • 是的,他们适合这种情况
      • 在func组件中如何使用?
      【解决方案6】:

      有多种存档方式,第一种方式是使用 CSS 使用此类

      @media screen and (max-width: 576px) {}
      

      此标签内的任何类只有在屏幕等于或小于 576px 时才可见

      第二种方式是使用事件监听器

      类似的东西

       constructor(props)
          {
              super(props);
      
              this.state = {
                  isToggle: null
              }
      
              this.resizeScreen = this.resizeScreen.bind(this); 
          }
          
          
           componentDidMount() {
      
              window.addEventListener("resize", this.resizeScreen());
      
          }
          
          
          resizeScreen() {
              if(window.innerWidth === 576)
              {
                  this.setState({isToggle:'I was resized'});
              }
              
          }

      即使使用事件监听器,我仍然更喜欢 CSS 方式,因为我们可以使用多种屏幕尺寸而无需进一步的 js 编码。

      我希望这会有所帮助!

      【讨论】:

        【解决方案7】:

        react-screentype-hook 库允许您开箱即用地执行此操作。 https://www.npmjs.com/package/react-screentype-hook

        您可以使用它提供的默认断点,如下所示

        const screenType = useScreenType();
        

        screenType 具有以下形状

          {
            isLargeDesktop: Boolean,
            isDesktop: Boolean,
            isMobile: Boolean,
            isTablet: Boolean
          }
        

        或者你甚至可以像这样配置你的自定义断点

        const screenType = useScreenType({
            mobile: 400,
            tablet: 800,
            desktop: 1000,
            largeDesktop: 1600
          });
        

        【讨论】:

          【解决方案8】:

          在Functional Component中,我们可以通过useTheme和useMediaQuery来检测屏幕大小。

          常量主题 = useTheme();
          const xs = useMediaQuery(theme.breakpoints.only('xs'));
          const sm = useMediaQuery(theme.breakpoints.only('sm'));
          const md = useMediaQuery(theme.breakpoints.only('md'));
          const lg = useMediaQuery(theme.breakpoints.only('lg'));
          const xl = useMediaQuery(theme.breakpoints.only('xl'));

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多