reactjs NextJS:在移动的上打开应用程序时组件无法正确切换

a64a0gku  于 2023-06-29  发布在  React
关注(0)|答案(3)|浏览(114)

我目前正在使用“React响应”来打开或关闭一些组件,这取决于应用程序是在桌面还是移动的上查看。
简化示例:

import { useMediaQuery } from 'react-responsive'

export default function MyComponent(props) {
    const isMobile = useMediaQuery({ query: `(max-width: 480px)` })

    return (
        <Wrapper>
            { isMobile ? <ComponentMobile /> : <ComponentDesktop /> }
        </Wrapper>
    )
}

当我在应用程序中从一个页面导航到另一个页面时,这很好,但是当我第一次打开网站时,即使我在移动的上,组件都是错误的(仍然呈现ComponentDesktop)。
我的猜测是,该组件是呈现服务器端,当它涉及到前端,它不更新。
做这件事的正确方法是什么?
非常感谢!

xa9qqrwz

xa9qqrwz1#

要解决这个问题,要么将该逻辑移动到useEffect(如果第一次渲染不需要它),要么延迟显示该组件,直到客户端渲染之后(如果HTML看起来损坏,直到useLayoutEffect运行)。
要从服务器呈现的HTML中排除需要布局效果的组件,可以使用showChild &&有条件地呈现它,并使用useEffect(()=> { setShowChild(true);这样,UI在水合之前不会出现损坏。

rjjhvcjd

rjjhvcjd2#

最近遇到了类似的问题,最终使用CSS显示或隐藏组件。Material UI有一个隐藏的组件,可以让你使用CSS轻松地做到这一点,但肯定有其他的解决方案。
有关多种可能的实现方式,请参阅Vercel的此视频:https://www.youtube.com/watch?v=K7g8X_VRDy8
检查用户代理也是可能的,但我个人喜欢CSS的想法,只是因为它根据屏幕的宽度自动显示或隐藏组件,但它肯定不是完美的。

n8ghc7c1

n8ghc7c13#

我必须在useMediaQuery()钩子周围创建一个useEffect() Package 器来解决水合问题。

import { useEffect, useState } from 'react';
import { useMediaQuery } from 'react-responsive';

export const IS_SERVER = typeof window === 'undefined';
export const MOBILE_SCREEN_MAX_WIDTH = 640;
export const SERVER_SIDE_IS_MOBILE_VALUE = true; // true - for mobile, false - for desktop

/**
 * Hook to detect onMobile vs. onDesktop using Media Query
 * @returns {boolean} true when on onMobile, false when on onDesktop
 */
function useOnMobileByMediaQuery() {
  const onMobile = useMediaQuery({ maxWidth: MOBILE_SCREEN_MAX_WIDTH });
  return onMobile;
}

/**
 * Hook to detect onMobile vs. onDesktop with Next.js workaround
 * @returns {boolean} true when on onMobile, false when on onDesktop
 */
function useOnMobileForNextJs() {
  const onMobile = useOnMobileByMediaQuery();
  const [onMobileDelayed, setOnMobileDelayed] = useState(SERVER_SIDE_IS_MOBILE_VALUE);

  useEffect(() => {
    setOnMobileDelayed(onMobile); // Next.js don't allow to use useOnMobileXxx() directly, so we need to use this workaround
  }, [onMobile]);

  return onMobileDelayed;
}

/**
 * We need a "smart export wrappers", because we can not use hooks on the server side
 */
export const useOnMobile = IS_SERVER ? () => SERVER_SIDE_IS_MOBILE_VALUE : useOnMobileForNextJs;

公共指南在这里https://gist.github.com/karpolan/9b9b2c781480cfc9a4bd2bfe62f332f3

相关问题