javascript 如何检测移动的SSR - reactjs

jgwigjjp  于 2023-03-21  发布在  Java
关注(0)|答案(1)|浏览(123)

我正在使用mobile-detect库和本教程:
link

/src/utiles/isMobile.tsx:

import MobileDetect from "mobile-detect";
import { GetServerSidePropsContext } from "next";

export const getIsSsrMobile = (context: GetServerSidePropsContext) => {
  const md = new MobileDetect(context.req.headers["user-agent"] as string);

  return Boolean(md.mobile());
};


/src/hooks/useIsMobile.js:

import { useContext } from "react";
import { IsSsrMobileContext } from "../contexts/isSsrMobileContext";

export const useIsMobile = () => {
    const isSsrMobile = useContext(IsSsrMobileContext);
  
    return isSsrMobile;
  };

/src/contexts/isSsrMobileContext.js:

import { createContext } from "react";

export const IsSsrMobileContext = createContext(false);

my `_app.tsx`:

import { IsSsrMobileContext } from "./../src/contexts/isSsrMobileContext";

function MyApp({ Component, pageProps }: AppProps <{ isSsrMobile: boolean }>): JSX.Element {

  return (
    <IsSsrMobileContext.Provider value={pageProps.isSsrMobile}>
    <Provider store={store}>

        <Component {...pageProps} />
           
    </Provider>
    </IsSsrMobileContext.Provider>
  );
}

export default MyApp;

在我的pages/index.tsx里面:
console.log(“useIsMobile”,useIsMobile())
显示为null

pzfprimi

pzfprimi1#

这里有另一种方法,你可以尝试不使用任何外部库。这不是最好的解决方案,但效果很好。我假设你的应用中有一个全局商店,我将在这个例子中使用effector,但这可以与你使用的任何商店提供商一起使用,只要确保在存储库上下文提供程序中执行此代码即可。但是你可以很容易地使用任何其他库,比如'styled-components'或者只是普通的CSS。我更喜欢@emotion,因为它可以在outb中工作。
这种方法背后的思想是首先呈现一个组件,该组件将依次呈现具有content属性的DOM元素,该属性的值将为desktopmobile,具体取决于媒体查询的结果。然后,您可以通过附加的ref访问content的值,最后,设置isMobile的值。
无论你在哪里有你的入口点,创建一个isMobile商店:

// PageShell.tsx (this returns `MainLayout` below)
. . .
export const $isMobile = createStore<boolean | null>(null);
export const setIsMobile = createEvent<boolean>();
$isMobile.on(setIsMobile, (_, isMobile) => isMobile);
. . .
import * as React from 'react';
import { useStore } from 'effector-react';
import IsMobileDeterminator from './IsMobileDeterminator';
import { $isMobile } from '../PageShell';

const MainLayout = React.memo(({ ...props }) => {
    const isMobile = useStore($isMobile);

    if (isMobile === null) {
        return <IsMobileDeterminator />;
    }

    if (isMobile) {
        return <PageShell>{'is mobile'}</PageShell>;
    }

    return <PageShell>{'is desktop'}</PageShell>;
});

export default MainLayout;

你的IsMobileDeterminator看起来像这样:

import * as React from 'react';
import styled from '@emotion/styled';
import { setIsMobile } from '../PageShell';

const IsMobileDeterminator = React.memo(() => {
    const ref = React.useRef<HTMLDivElement>(null);

    React.useEffect(() => {
        if (ref.current) {
            const isMobile = getComputedStyle(ref.current).content === `"mobile"`;

            setIsMobile(isMobile);
        }
    }, [ref.current]);

    return <IsMobileDeterminatorContainer ref={ref} />;
});

export default IsMobileDeterminator;

const IsMobileDeterminatorContainer = styled.div`
    display: none;
    content: 'desktop';
    
    @media(max-width: 767px) {
        content: 'mobile'
    }
`;

现在,您可以在应用中的任何位置使用以下命令访问isMobile的值:

const isMobile = useStore($isMobile);

如果你想让IsMobileDeterminator像钩子一样工作,你可以像这样改变它,

import * as React from 'react';
import styled from '@emotion/styled';
import { setIsMobile } from '../../../../renderer/usePageContext';

const IsMobileDeterminator = React.memo(() => {
    const ref = React.useRef<HTMLDivElement>(null);

    const handleGetIsMobile = React.useCallback(() => {
        if (ref.current) {
            const isMobile = getComputedStyle(ref.current).content === `"mobile"`;

            setIsMobile(isMobile);
        }
    }, []);

    const handleResize = React.useCallback(handleGetIsMobile, []);

    React.useEffect(() => {
        if (ref.current) {
            window.addEventListener('resize', handleResize);
            handleGetIsMobile();
        }

        return () => {
            if (ref.current) {
                window.removeEventListener('resize', handleResize);
            }
        };
    }, [ref.current]);

    return <IsMobileDeterminatorContainer ref={ref} />;
});

export default IsMobileDeterminator;

const IsMobileDeterminatorContainer = styled.div`
    display: none;
    content: 'desktop';
    @media (max-width: 767px) {
        content: 'mobile';
    }
`;

改变你的切入点:

import * as React from 'react';
import { useStore } from 'effector-react';
import IsMobileDeterminator from './IsMobileDeterminator';
import { $isMobile } from '../PageShell';

const MainLayout = React.memo(({ ...props }) => {
    const isMobile = useStore($isMobile);

    const content = [<IsMobileDeterminator />];

    if (isMobile !== null) {
        content.push(
            isMobile
                ? <PageShell>{'is mobile'}</PageShell>
                : <PageShell>{'is desktop'}</PageShell>
        );
    }

    return <>{content}</>
});

export default MainLayout;

我在这里使用767px作为唯一的断点,但我相信如果需要的话,您可以找出如何让它与其他断点一起工作。

相关问题