简体   繁体   English

如何有条件地在 gatsby 中呈现移动导航?

[英]how to conditionally render a mobile nav in gatsby?

I am new to gatsby and server side rendering, although I've worked with react quite a bit before.我是 gatsby 和服务器端渲染的新手,尽管我之前已经使用过很多 react。 I wrote a bit of code that checks for the window size and then renders either the nav or the mobile nav based on the width.我编写了一些代码来检查 window 大小,然后根据宽度呈现导航或移动导航。 However, when I tried to test-deploy, I discovered that the window object is not available when you use server side rendering.但是,当我尝试测试部署时,我发现在使用服务器端渲染时,window object 不可用。 My question is, is there any way i can modify my code to still work?我的问题是,有什么办法可以修改我的代码以使其仍然有效? or should I just rebuild everything with sass and media queries?还是我应该使用 sass 和媒体查询重建所有内容?

 import React, { useState, useEffect } from "react" import { Link, graphql, useStaticQuery } from "gatsby" // import "./header.module.scss" import HeaderStyles from "./header.module.scss" import Logo from "../images/newlogo@2x.png" import Nav from "./nav" const Header = () => { const data = useStaticQuery(graphql` query MyQuery { site { siteMetadata { title } } } `) const [isDesktop, setDesktop] = useState(window.innerWidth > 768) const updateMedia = () => { setDesktop(window.innerWidth > 768) } useEffect(() => { window.addEventListener("resize", updateMedia) return () => window.removeEventListener("resize", updateMedia) }) const [menuActive, setMenuState] = useState(false) return ( <header className={menuActive? HeaderStyles.mobileNav: HeaderStyles.header} > <Link to="/" className={HeaderStyles.title}> {/* {data.site.siteMetadata.title} */} <img src={Logo} height="60" /> </Link> {isDesktop? ( <Nav /> ): ( //hamburger <div onClick={() => setMenuState(.menuActive)} className={`${HeaderStyles?navIcon3} ${ menuActive. HeaderStyles:open? "" }`} > <span></span> <span></span> <span></span> <span></span> </div> )} {menuActive: <Nav /> : null} </header> ) } export default Header

You can't use the window object (or other global objects such as document ) directly in your code.您不能在代码中直接使用window object (或其他全局对象,例如document This is because gatsby develop is rendered by the browser, where there's a window object, however gatsby build occurs in the Node server (your machine or you build system) where's there's no window .这是因为gatsby develop是由浏览器呈现的,其中有一个window object,但是gatsby build发生在节点服务器(您的机器或您构建的系统)中,没有window

If you don't want to redo your code with SCSS and mediaqueries (preferred version and more native), you need to make a condition above every use of window object.如果您不想使用 SCSS 和媒体查询(首选版本和更多本机版本)重做代码,则需要在每次使用window object 之前创建一个条件。 In your case, you need to make it when the DOM tree is loaded ( useEffect with empty deps , [] ).在您的情况下,您需要在加载 DOM 树时进行(使用空depsuseEffect[] )。 Something like this should work:像这样的东西应该工作:

import React, { useState, useEffect } from "react"
import { Link, graphql, useStaticQuery } from "gatsby"
// import "./header.module.scss"
import HeaderStyles from "./header.module.scss"
import Logo from "../images/newlogo@2x.png"
import Nav from "./nav"
const Header = () => {
  const data = useStaticQuery(graphql`
    query MyQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
  const [isDesktop, setDesktop] = useState(false)

  useEffect(()=>{
    if(typeof window !== 'undefined'){
      setDesktop(window.innerWidth > 768)
    }
  },[])

  const updateMedia = () => {
    setDesktop(window.innerWidth > 768)
  }

  useEffect(() => {
    window.addEventListener("resize", updateMedia)
    return () => window.removeEventListener("resize", updateMedia)
  })
  const [menuActive, setMenuState] = useState(false)
  return (
    <header
      className={menuActive ? HeaderStyles.mobileNav : HeaderStyles.header}
    >
      <Link to="/" className={HeaderStyles.title}>
        {/* {data.site.siteMetadata.title} */}
        <img src={Logo} height="60" />
      </Link>
      {isDesktop ? (
        <Nav />
      ) : (
        //hamburger
        <div
          onClick={() => setMenuState(!menuActive)}
          className={`${HeaderStyles.navIcon3} ${
            menuActive ? HeaderStyles.open : ""
          }`}
        >
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
      )}
      {menuActive ? <Nav /> : null}
    </header>
  )
}

export default Header

Keep in mind that this approach will create a small blink (a few ms ) until the code knows what's the window 's with and, depending on your use-case, it may not work when resizing it, we should readapt a little bit the code to make it functional there.请记住,这种方法会产生一个小闪烁(几ms ),直到代码知道window是什么,并且根据您的用例,它在调整大小时可能不起作用,我们应该重新调整一下代码使它在那里起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM