🐈

React用のデバイス判別フック作ったので、みんなに共有

に公開

経緯

もともと、react-device-detectというライブラリを利用させてもらってたんだけど、思った動作をしないので(使い方が悪かったのかも?)、自分で作りました。

前提環境

  • nodejs・npmインストール済み
  • React

インストール

全体コード
'use client';
import { useCallback, useEffect, useState } from 'react';

interface ReturnDeviceType {
    error: unknown;

    isMobile: boolean;
    isAndroid: boolean;
    isIos: boolean;
    isTablet: boolean;
    isDesktop: boolean;
    isUnknown?: boolean;
}

const DEVICE_UA_TYPE = {
    desktop: /Windows NT|Macintosh|Linux|CrOS/i,
    tablet: {
        primary: /iPad|Android(?!.*Mobile)|Windows.*Touch/i,
        secondary: /Macintosh/i,
    },
    mobile: {
        all: /iPhone.*Mobile|Android.*Mobile|Windows Phone|BlackBerry/i,
        android: /Android.*Mobile/i,
        iphone: /iPhone.*Mobile/i,
    },
};

const useDeviceType = (deviceUnknowNullable = false) => {
    const [loaded, setLoaded] = useState<boolean>(false);
    const [deviceInfo, setDeviceInfo] = useState<ReturnDeviceType>({
        // 状態値
        error: null,
        // モバイル
        isMobile: false,
        isAndroid: false,
        isIos: false,
        // タブレット
        isTablet: false,
        // PC
        isDesktop: false,
        isUnknown: false,
    });

    const getDeviceType = useCallback(() => {
        const ua = navigator.userAgent;
        const width = window.innerWidth;
        const hasTouch = 'ontouchstart' in window;

        const testRegex = (type: RegExp) => type.test(ua);
        const mobileRgx = DEVICE_UA_TYPE.mobile;

        const newDeviceType: Partial<ReturnDeviceType> = {
            isMobile: false,
            isAndroid: false,
            isIos: false,
            isTablet: false,
            isDesktop: false,
            isUnknown: false,
        };

        try {
            // PC判定
            if (testRegex(DEVICE_UA_TYPE.desktop) && width >= 960) {
                newDeviceType.isDesktop = true;
            }

            // タブレット
            else if (
                testRegex(DEVICE_UA_TYPE.tablet.primary) ||
                (testRegex(DEVICE_UA_TYPE.tablet.secondary) && width <= 1024 && hasTouch)
            ) {
                newDeviceType.isTablet = true;
            }

            // モバイル
            else if (testRegex(mobileRgx.all)) {
                newDeviceType.isMobile = true;

                // android
                if (testRegex(mobileRgx.android)) {
                    newDeviceType.isAndroid = true;
                } else if (testRegex(mobileRgx.iphone)) {
                    newDeviceType.isIos = true;
                }
            } else newDeviceType.isUnknown = true;

            if (!deviceUnknowNullable) {
                delete newDeviceType.isUnknown;
            }

            setDeviceInfo(newDeviceType as ReturnDeviceType);
        } catch (err) {
            console.error(err);
            setDeviceInfo((prevState) => ({
                ...prevState,
                error: err,
            }));
        }
    }, [deviceUnknowNullable]);

    useEffect(() => {
        getDeviceType();
        setLoaded(true);
    }, [getDeviceType]);

    return { loaded, ...deviceInfo };
};

export default useDeviceType;

  1. 上のコードをコピー
  2. 好きな場所に、useDeviceType.tsというファイルを作成
    ※ファイル名は何でもいいですが、変更したらexport defaultの変数名?も変更してください
  3. あとは、足りないライブラリとかをインストールしたら使用できます。

使い方

通常のカスタムフックと使い方は一緒です。

const { loaded, error, isTablet, isDesktop } = useDeviceType();

isUnknown

このカスタムフックには、isUnknownというプロパティがあります。
端末がなにか不明だった場合のため、エラーではなくisUnknownがbooleanで返ります。

基本的には、このプロパティはundefinedになっていますが、下のようにTrueに変更すればbooleanが返るようになります。

const { isUnknown, ... } = useDeviceType(true);

テストコード

export default function TestNode() {
    const dt = useDeviceType();

    useEffect(() => {
        console.log(dt)![](https://storage.googleapis.com/zenn-user-upload/16ad3b254b3d-20250908.png);
    }, []);

    return(<></>)
}

上のコードを試してみて、下のようなログが出たら正常に動いています。
※環境によって変わる可能性があります。

備考

不明点があれば、お気軽にご連絡ください

Discussion