admin管理员组

文章数量:1128470

In ReactJS, is there a way to determine if the website is being viewed on mobile or desktop? Because, depending on which device I would like to render different things.

Thank you

In ReactJS, is there a way to determine if the website is being viewed on mobile or desktop? Because, depending on which device I would like to render different things.

Thank you

Share Improve this question asked Sep 11, 2016 at 11:02 user3259472user3259472 1
  • 12 I am not cool with a lot of answers, that just depend on the screen width. If you go to landscape mode for example, I still want to distinguish between a phone and a desktop version, especially with the control capabilities. A clean setup should be able to distinguish between: mobile/tablet/desktop portrait/landscape touch/no touch keys/nokeys least but not last pixel based breakpoints – mapadj Commented Nov 3, 2021 at 11:52
Add a comment  | 

22 Answers 22

Reset to default 212

Simple solution using react hooks

const [width, setWidth] = useState<number>(window.innerWidth);

function handleWindowSizeChange() {
    setWidth(window.innerWidth);
}
useEffect(() => {
    window.addEventListener('resize', handleWindowSizeChange);
    return () => {
        window.removeEventListener('resize', handleWindowSizeChange);
    }
}, []);

const isMobile = width <= 768;

You can use React Device Detect Package

This package uses the user-agent of the browser rather than the screen size.

This can be helpful when wanting to display different things if on desktop vs mobile or certain links based on the device

Installation

To install, you can use npm or yarn:

# For NPM:
npm install react-device-detect --save

# For Yarn
yarn add react-device-detect

Usage

Example:

import {BrowserView, MobileView} from 'react-device-detect';

const MyComponent = () => {
    return (
        <>
            <BrowserView>
                <h1>This is rendered only in browser</h1>
            </BrowserView>
            <MobileView>
                <h1>This is rendered only on mobile</h1>
            </MobileView>
        </>
    );
};

if you don't need a view, you can use isMobile for conditional rendering

import {isMobile} from 'react-device-detect';

const MyComponent = () => {
    if(isMobile) {
        return (
            <div> This content is available only on mobile</div>
        )
    }
    return (
        <div> content... </div>
    );
};

Taken from React Device Detect README with a little modification

I further enhanced Volobot's answer. I'd created a hook as below and it works like charm :)

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

const useCheckMobileScreen = () => {
    const [width, setWidth] = useState(window.innerWidth);
    const handleWindowSizeChange = () => {
            setWidth(window.innerWidth);
    }

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

    return (width <= 768);
}

export default useCheckMobileScreen

What you are looking for is called react-responsive. You can find it here

Here is how to use quick guide from their repo:

var MediaQuery = require('react-responsive');

var A = React.createClass({
  render: function(){
    return (
      <div>
        <div>Device Test!</div>

        <MediaQuery minDeviceWidth={1224}>
          <div>You are a desktop or laptop</div>
        </MediaQuery>
        <MediaQuery maxDeviceWidth={1224}>
          <div>You are a tablet or mobile phone</div>
        </MediaQuery>

        <MediaQuery orientation='portrait'>
          <div>You are portrait</div>
        </MediaQuery>
        <MediaQuery orientation='landscape'>
          <div>You are landscape</div>
        </MediaQuery>

        <MediaQuery minResolution='2dppx'>
          <div>You are retina</div>
        </MediaQuery>
      </div>
    );
  }
});

Tablets has big screens but they act like mobile phones, so if you want to detect touch screen instead of the size of the screen:

const isTouchScreenDevice = () => {
    try{
        document.createEvent('TouchEvent');
        return true;
    }catch(e){
        return false;
    }
}

Why to complicate things when you can use one line of vanilla javascript code?

Use window.screen object to get width of current screen. For example window.screen.width will return value of current width of client in pixels.

Use it inside if (window.screen.width >= 1280) { /* conditional statements */ }

I hope that it helps. Thank you :-)

Create a Custom Hook and Listen to Resize, load, orientationchange and reload will rerender the component where you have used this hook.

import { useEffect, useState } from 'react';

const useIsMobile = (breakpoint = 640) => {
  const checkForDevice = () => window.innerWidth < breakpoint;

  const [isMobile, setIsMobile] = useState(checkForDevice());

  useEffect(() => {
    const handlePageResized = () => {
      setIsMobile(checkForDevice());
    };

    if (typeof window !== 'undefined') {
      window.addEventListener('resize', handlePageResized);
      window.addEventListener('orientationchange', handlePageResized);
      window.addEventListener('load', handlePageResized);
      window.addEventListener('reload', handlePageResized);
    }

    return () => {
      if (typeof window !== 'undefined') {
        window.removeEventListener('resize', handlePageResized);
        window.removeEventListener('orientationchange', handlePageResized);
        window.removeEventListener('load', handlePageResized);
        window.removeEventListener('reload', handlePageResized);
      }
    };
  }, []);

  return {
    isMobile,
  };
};

export default useIsMobile;

We can make a simple custom hook which leverages Interaction Media Features using the MatchMedia API

function useDeviceDetect() {
  const [isTouchDevice, setIsTouchDevice] = React.useState(false);
  React.useEffect(() => {
    if (!window.matchMedia) return;
    setIsTouchDevice(window.matchMedia("(pointer:coarse)").matches);
  }, []);

  return isTouchDevice;
}

The idea here is to target devices based on their capabilities (as apposed to say, checking the width or resolution of the device/viewport which tend to be moving targets)

For touch devices, the accuracy of the primary input mechanism of the device is limited, so (pointer:coarse) would match.

Codesandbox

Here's an example usage:

function App() {
  const isTouchDevice = useDeviceDetect();
  console.log({ isTouchDevice });
  return (
    <div>{`I am ${isTouchDevice ? "" : "NOT"} a touch device`}</div>
  );
}

I used this method for React and it works great in 2020. Thanks @Anubahav Gupta

npm install react-responsive --save

Then create component:

import React, { Fragment, Component } from 'react';
import MediaQuery from 'react-responsive';

class MyMediaQuery extends Component {
    render() {
        return (
            <Fragment>
                <div>Device Test!</div>

                <MediaQuery minDeviceWidth={1224}>
                    <div>You are a desktop or laptop</div>
                </MediaQuery>
                <MediaQuery maxDeviceWidth={1224}>
                    <div>You are a tablet or mobile phone</div>
                </MediaQuery>

                <MediaQuery orientation='portrait'>
                    <div>You are portrait</div>
                </MediaQuery>
                <MediaQuery orientation='landscape'>
                    <div>You are landscape</div>
                </MediaQuery>

                <MediaQuery minResolution='2dppx'>
                    <div>You are retina</div>
                </MediaQuery>
            </Fragment>
        );
    }
}

export default MyMediaQuery;

It works as-is on any page loaded but can also be imported into another file with:

import MyMediaQuery from '.newFileName';

Then used anywhere as:

<MyMediaQuery />

A modified version of the top answer, but without using the width as the state, and updating it on every resize. This way the state is only updated when window.innerWidth <= 768 changes.

  const [ isMobile, setIsMobile ] = useState<boolean>(window.innerWidth <= 900);
  
  const handleResize = () => setIsMobile(window.innerWidth <= 900);

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

This is not specifc to React but here is my js fonction:

export const isMobile = () => window.matchMedia && window.matchMedia("(max-width: 480px)").matches

If all you really want is

  • to know if it's a mobile,
  • you're ok with solution using screen size as a proxy,
  • you don't care about window size updates, rotation, etc,

many other answers may be overengineered for your case. Here's a possible two-liner:

const [width, height] = [window.screen.width, window.screen.height];
const isMobile = Math.min(width, height) < 768;
console.log(Math.min(width, height));

The previous answers (apart from one that uses a package) all appear to simply be checking the screen width when determining if the client is mobile or not. Someone could be accessing from a tablet in landscape mode which would be a mobile device but be classified as desktop with that approach.

Here is an approach that uses the user-agent to classify the device as one of Mobile, Tablet or Desktop. Abstracted as a custom hook for convenience.

// hooks.js

import { useState, useEffect } from 'react';

export function useDeviceType() {
  const [device, setDevice] = useState('');

  useEffect(() => {
    function handleDeviceDetection() {
      const userAgent = navigator.userAgent.toLowerCase();
      const isMobile = /iphone|ipad|ipod|android|windows phone/g.test(userAgent);
      const isTablet =
        /(ipad|tablet|playbook|silk)|(android(?!.*mobile))/g.test(userAgent);

      if (isMobile) setDevice('Mobile');
      else if (isTablet) setDevice('Tablet');
      else setDevice('Desktop');
    }

    handleDeviceDetection();
    window.addEventListener('resize', handleDeviceDetection);

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

  return device;
}

And then to implement it:

// app.js or wherever

const deviceType = useDeviceType();
console.log(deviceType);
// prints 'Mobile', 'Tablet' or 'Desktop' depending on device.

Looks weird but it works like a charm. No hooks, no packages and no import :)

function isMobile() {
  if (
    /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
      navigator.userAgent
    ) ||
    /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw(n|u)|c55\/|capi|ccwa|cdm|cell|chtm|cldc|cmd|co(mp|nd)|craw|da(it|ll|ng)|dbte|dcs|devi|dica|dmob|do(c|p)o|ds(12|d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(|_)|g1 u|g560|gene|gf5|gmo|go(\.w|od)|gr(ad|un)|haie|hcit|hd(m|p|t)|hei|hi(pt|ta)|hp( i|ip)|hsc|ht(c(| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i(20|go|ma)|i230|iac( ||\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|[a-w])|libw|lynx|m1w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|mcr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|([1-8]|c))|phil|pire|pl(ay|uc)|pn2|po(ck|rt|se)|prox|psio|ptg|qaa|qc(07|12|21|32|60|[2-7]|i)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h|oo|p)|sdk\/|se(c(|0|1)|47|mc|nd|ri)|sgh|shar|sie(|m)|sk0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h|v|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl|tdg|tel(i|m)|tim|tmo|to(pl|sh)|ts(70|m|m3|m5)|tx9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas|your|zeto|zte/i.test(
      navigator.userAgent.substr(0, 4)
    )
  )
    return true;
  else return false;
}

Yet another non answering answer: maxTouchPoints

const inMobileDevice = window.navigator.maxTouchPoints > 2;

Why?

Almost all other answers are right. You can't know. But...

  1. if you want to detect a cellphone or tablet in a standard one as a mobile
  2. if you want to detect a notebook or desktop PC, Windows or Linux in a standard configuration (not emulating) as non mobile
  3. if you want to detect a navigator used in a notebook that is not maximized and which window has a narrow width as non mobile
  4. you don't care about bizarre configs or emulators then
  5. you want to work in devices that don't exists today.

This is your solution.

Many of the given answers fails in 3 or depends on third party libraries with an explicit list of existing devices (and fails in 5).

ref: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/maxTouchPoints

const getNumberDesignRequest = screenWidth => {
  let numberDesignRequest = 20
  if (screenWidth >= 1280 && screenWidth < 1525) {
    numberDesignRequest = 21
  }
  
  return numberDesignRequest
}

const ScreenWidth = () => {
  const [screenWidth, setScreenWidth] = useState(window.innerWidth)

  useLayoutEffect(() => {
    const handleResize = () => {
      const { innerWidth } = window
      setScreenWidth(innerWidth)
    }

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

  return screenWidth
}

const FuzzySearch = () => {
  const screenWidth = ScreenWidth()
const numberDesignRequest = getNumberDesignRequest(screenWidth)

The solution for this is to check the size of the screen

const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
const MAX_WIDTH_FOR_MOBILE = 900;

Now check the width of the screen with the max width

return (
   width < MAX_WIDTH_FOR_MOBILE ? <Mobile /> : <Desktop />
)

i wanted to show a single button in mobile version and am a beginner in react so most of solutions didn't worked for me. I instead went with a simple css approach:

 <button className="disblock_mobile">my data </button>
.disblock_mobile{display: none;}

@media only screen and (max-width: 767px) {
    .disblock_mobile{display: block;}
}

This works in plain javascript:

let width = window.innerWidth;

function handleWindowSizeChange() {
    width = window.innerWidth;
}

window.addEventListener('resize', handleWindowSizeChange);

// This is to remove the event listener when the page is closed or navigated away from.
window.onbeforeunload = function () {
    window.removeEventListener('resize', handleWindowSizeChange);
};

const isMobile = function() {
    return width <= 768;
};

I created a custom hook for this:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import { useEffect, useState } from 'react';

const useIsMobile = (width)=> {
  const [isMobile, setIsMobile] = useState(window.innerWidth <= width);

  useEffect(() => {
    function handleResize() {
      setIsMobile(window.innerWidth <= 768);
    }

    // Add event listener to window resize
    window.addEventListener('resize', handleResize);

    // Clean up the event listener on component unmount
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return isMobile;
}

export default useIsMobile;

here

You can use it in your component : You can use this way

I have found a method to detect device type (mobile or desktop). If you rely solely on the User-Agent to detect the device type, it can easily be spoofed using browser developer tools. Similarly, if you use the ontouch event for device detection, it can be tricked by enabling touch simulation in the browser.

To overcome these limitations, I have discovered a combination method that is supported in most browsers and is safer and more reliable than other approaches:

import { useEffect, useState } from 'react';

type TDeviceType = 'web' | 'mobile';
export const useUserAgentStrict = (): TDeviceType => {
  const [deviceType, setDeviceType] = useState<TDeviceType>('web');

  useEffect(() => {
    const getUserAgentStrictly = () => {
      const userAgent = navigator.userAgent;
      const platform = navigator.platform;
      if (
        !/Android|android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
          userAgent
        ) ||
        (platform && platform.match(/(win|mac|linux x86_64)/i))
      ) {
        return 'web';
      } else {
        return 'mobile';
      }
    };

    const device = getUserAgentStrictly();
    setDeviceType(device);
  }, []);

  return deviceType;
};

export default useUserAgentStrict;

Explanation: How It Works:

This hook uses the User-Agent to detect the device type, but also checks whether the platform is a desktop or not. This combination makes sure that even if the User-Agent is spoofed, additional checks are performed to ensure the accuracy of the detection. Why Is This Method Better?

Since it’s not solely relying on the User-Agent or touch events, it's a safer method compared to simpler approaches. Most browsers provide this information accurately, and it’s not easily spoofed. How to Use:

This hook can be used to detect whether the user is on a mobile or desktop device within various components. You can easily display different user interfaces or apply different styles and behaviors to your website depending on the device type.

browser support

React doesn't do this, React is only the View in MVC. Determination logic (controlling what SHOULD be viewed) is the role of the Controller. React doesn't implement a controller but thinks that should be done by the rest of the application, so you should add some other code controlling the context of the React component or even using different components for different devices.

本文标签: