如何在页面加载时设置 useState 挂钩的状态?

Posted

技术标签:

【中文标题】如何在页面加载时设置 useState 挂钩的状态?【英文标题】:How to set the state of a useState hook on page load? 【发布时间】:2022-01-16 01:22:53 【问题描述】:

我正在尝试创建响应式导航。它有一个_函数:

    在屏幕宽度上显示导航链接 > 页面加载时为 768 像素 在屏幕宽度 如果在切换到大屏幕时未在小屏幕上打开导航,请关闭导航(简单地说,如果用户在移动设备上打开导航链接,切换到更大的屏幕尺寸,然后返回移动设备,导航链接应该被隐藏再次)

我已经完成了 99% 的工作,但我认为我这样做的方式很老套,因为当我在较小的屏幕上时,导航链接会闪烁片刻,然后消失。这显然不是我想要的。

下面是一个精简的、没有样式的 sn-p 以便于调试:

export const Nav = () => 
  const [showNavOnClick, setShowNavOnClick] = useState(false)
  const [hamburgerOpen, setHamburgerOpen] = useState(false)
  const [showNavOnScreenSize, setShowNavOnScreenSize] = useState(true)

  const toggleMenu = () => 
    setShowNavOnClick(!showNavOnClick)
    setHamburgerOpen(!hamburgerOpen)
  

  useEffect(() => 
    // This line solves all 3 goals, but on page load, the nav links appear, then dissapear in a split moment. 
    if (window.innerWidth < 768) setShowNavOnScreenSize(false)

    const handleResize = () => 
      if (window.innerWidth > 768) 
        setShowNavOnScreenSize(true)
        setShowNavOnClick(false)
       else if (window.innerWidth < 768) 
        setShowNavOnScreenSize(false)
      
    

    window.addEventListener('resize', handleResize)

    return () => 
      window.removeEventListener('resize', handleResize)
    
  , [])

  return (
    <nav>
      <a href="/">Home</a>
      <button onClick=toggleMenu>*</button>
      <a
        href="/about"
        className=`$
          showNavOnScreenSize ||
          showNavOnClick && showNavOnScreenSize != showNavOnClick)
            ? 'visible'
            : 'hidden'
        `>
        About
      </a>
    </nav>
  )


以下是显示故障的视频:

当我添加const [showNavOnScreenSize, setShowNavOnScreenSize] = useState(window.innerWidth &gt;= 768) 时,我收到window is not defined 的错误

【问题讨论】:

【参考方案1】:

您可以通过更改要根据宽度计算的状态的默认值而不是硬编码的true 来解决此问题:

const [showNavOnScreenSize, setShowNavOnScreenSize] = useState(window.innerWidth >= 768)

如有必要,您可以以类似的方式为其他状态设置默认值。

编辑:或者,尝试使用布局效果,以便重新渲染是同步的:

const [showNavOnScreenSize, setShowNavOnScreenSize] = useState(true)

useLayoutEffect(() => 
    if (window.innerWidth < 768) setShowNavOnScreenSize(false)
    // ...

【讨论】:

我收到window is not defined 的错误。我更新了我的帖子以显示带有该错误消息的图片。 你在使用服务器端渲染吗? 我正在使用 Next.js,但一切都在客户端呈现 看起来有效,但我不知道为什么。

以上是关于如何在页面加载时设置 useState 挂钩的状态?的主要内容,如果未能解决你的问题,请参考以下文章

使用立即需要该状态进行 API 调用的 useState 挂钩时,如何等待 setState 调用完成?

更改输入的状态会延迟一个字符(useState 挂钩)

如何防止在单击事件上触发两个相同的 useState 挂钩

如何使用 useState 挂钩更新状态而不重新渲染

在 useState 钩子中反应设置状态

React useState导致渲染循环