javascript 在Next.js中根据屏幕大小渲染不同的组件

k4ymrczo  于 5个月前  发布在  Java
关注(0)|答案(2)|浏览(74)

我试图根据屏幕宽度< 768p来渲染一个组件。
如果小于768p,则加载汉堡菜单。如果不小于768p,则加载整个菜单。
下面是我使用的代码。问题是,当页面第一次加载时,我无法观察到变化。但是当我将浏览器屏幕缩小,然后将其增加到原始大小时,效果就发生了。
我认为这是因为React是在服务器端渲染的。但仍然不明白为什么它的工作原理是让屏幕变小,然后再变大。

import "twin.macro"
import { Global, css } from "@emotion/core"

import { useState, useEffect } from "react"

const Navbar = () => {
  const useWindowDimensions = () => {
    const hasWindow = typeof window !== "undefined"

    function getWindowDimensions() {
      const width = hasWindow ? window.innerWidth : null
      const height = hasWindow ? window.innerHeight : null
      return {
        width,
        height,
      }
    }

    const [windowDimensions, setWindowDimensions] = useState(
      getWindowDimensions()
    )

    useEffect(() => {
      if (hasWindow) {
        function handleResize() {
          setWindowDimensions(getWindowDimensions())
        }

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

    return windowDimensions
  }

  const { height, width } = useWindowDimensions()
  const breakpoint = 768

  return (
    <div>
      {width <= breakpoint ? (
        <div>
          <HamburgerMenu />
        </div>
      ) : (
        <div>
           <FullMenu />
        </div>
  )
}

export default Navbar

字符串
有没有一种方法可以强制Next.js应用程序在第一次渲染时应用效果?

new9mtju

new9mtju1#

Next.js是通用的,这意味着它首先在服务器端执行代码,然后在客户端执行。
所以第一次不能访问window,所以windowDimensions的值是null
当你调整大小的时候,你改变了状态,让你的应用重新渲染,所以它变成了客户端渲染=>你可以访问窗口,然后你的代码工作

aamkag61

aamkag612#

完成上面的答案,是的,使用useEffect或useLayoutEffect,这里是我自己的钩子:

import { useState, useEffect, useLayoutEffect, useCallback } from 'react';
import throttle from 'lodash/throttle';

type ScreenSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';

interface ScreenDimension {
  screenSize: ScreenSize | undefined;
  width: number | undefined;
  height: number | undefined;
}

function getScreenSize(width: number): ScreenSize {
  if (width >= 1536) {
    return '2xl';
  } else if (width >= 1280) {
    return 'xl';
  } else if (width >= 1024) {
    return 'lg';
  } else if (width >= 768) {
    return 'md';
  } else if (width >= 640) {
    return 'sm';
  } else {
    return 'xs';
  }
}

export function useScreenSize(): ScreenDimension {
  const [dimension, setDimension] = useState<ScreenDimension>({
    screenSize: undefined, // Default to 'xs'
    width: undefined,
    height: undefined,
  });

  // Define the resize handler
  const handleResize = useCallback(() => {
    if (typeof window !== 'undefined') {
      const newSize = getScreenSize(window.innerWidth);
      setDimension({
        screenSize: newSize,
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }
  }, []);

  // Create a throttled version of the resize handler
  const throttledHandleResize = useCallback(throttle(handleResize, 300), [
    handleResize,
  ]);

  useLayoutEffect(() => {
    if (typeof window !== 'undefined') {
      // Run the handler immediately to set the initial screen size
      handleResize();

      // Set up the throttled resize listener
      window.addEventListener('resize', throttledHandleResize);

      // Clean up
      return () => {
        throttledHandleResize.cancel(); // Cancel the throttle function on cleanup
        window.removeEventListener('resize', throttledHandleResize);
      };
    }
  }, [throttledHandleResize]);

  return dimension;
}

字符串

相关问题