next.js 错误:useMediaQuery是一个仅限客户端的钩子

ogsagwnx  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(96)

我试图使用NextJS 13.4.7创建一个应用程序,并使用useMediaQuery钩子来检测视图是否是移动的。我的组件不是服务器组件,但我一直得到client-only钩子错误。现在我的客户端组件是服务器组件的一部分,但从文档中看,它似乎是允许的。我错过了什么吗?下面是代码,

"use client";

import { useContext, useState, useEffect } from "react";
import PageDataContext from "@/contexts/PageDataContext";
import useMediaQuery from "@/hooks/useMediaQuery";
import { motion } from "framer-motion";

export default function Header() {
  const content = useContext(PageDataContext);
  const isSmallDevice = useMediaQuery("only screen and (max-width : 991px)");
  const [hideNav, setHideNav] = useState(isSmallDevice);
  const { home: homeContent } = content;
  const { navigation: navigationContent } = content;
  const { name } = homeContent;
  const [firstName, lastName] = name.split(" ");

  const onTheRight = { x: "100%" };
  const inTheCenter = { x: 0 };
  const onTheLeft = { x: "-100%" };

  const transition = { duration: 0.6, ease: "easeInOut" };

  const variants = {
    open: { opacity: 1, x: "0%" },
    closed: { opacity: 0, x: "100%" },
  };
  const toggleSideNav = () => {
    setHideNav(!hideNav);
  };

  useEffect(() => {
    setHideNav(isSmallDevice);
  }, [isSmallDevice]);

  return (
    <header id="site_header" className="header">
      <div className="header-content clearfix">
        <div className="text-logo">
          <a href="/">
            <div className="logo-symbol">{firstName[0].toUpperCase()}</div>
            <div className="logo-text">
              {firstName} <span>{lastName}</span>
            </div>
          </a>
        </div>
        <motion.div
          animate={hideNav ? "closed" : "open"}
          variants={variants}
          style={{
            position: "fixed",
            width: "100%",
            height: "calc(100% - 52px)",
            top: "52px",
            left: "auto",
          }}
        >
          <div className="site-nav">
            <ul className="leven-classic-menu site-main-menu">
              {navigationContent.map((item, idx) => (
                <li className="menu-item" key={"header_key_" + idx}>
                  <a href={item.url}>{item.title}</a>
                </li>
              ))}
            </ul>
          </div>
        </motion.div>
        <a className="menu-toggle mobile-visible" onClick={toggleSideNav}>
          <i className="fa fa-bars"></i>
        </a>
      </div>
    </header>
  );
}

字符串

9rygscc1

9rygscc11#

我遇到了同样的问题。这是因为useMediaQuery同时呈现服务器端和客户端。即使你给予“use client”指令,如果它在ssr所在的地方工作,也会发生这个错误。
作为解决方案,您可以创建一个自定义钩子,并通过动态导入使用此钩子:

自定义钩子示例:

"use client";
import useMediaQuery from "@/hooks/useMediaQuery";

const useDevice = () => {
  const isMobile = useMediaQuery("only screen and (max-width : 767px)");
  const isTablet = useMediaQuery(
    "only screen and (min-width : 768px) and (max-width : 1024px)"
  );
  const isDesktop = useMediaQuery(
    "only screen and (min-width : 1025px) and (max-width : 2379px)"
  );
  const isDesktopLarge = useMediaQuery("only screen and (min-width : 2380px)");

  return { isMobile, isTablet, isDesktop, isDesktopLarge };
};

export default useDevice;

字符串

用法:

"use client";
const useDevice = dynamic(() => import("@/app/hooks/useDevice"), {
  ssr: false
});

export default function Header() {
  const device = useDevice();
  console.log(device?.isDesktop)

  ...

}

相关问题