繁体   English   中英

Gatsby:基于 window.innerWidth 行为不端的 React 条件渲染

[英]Gatsby: React conditional rendering based on window.innerWidth misbehaving

基于window.innerWidth的组件的条件渲染似乎无法在基于 Gatsby 的网站的生产版本中按预期工作。

我用来检查视口宽度的钩子,以及对 window 全局的额外检查以避免 Gatsby 节点生产构建错误,如下所示:

import { useState, useEffect } from 'react'

const useWindowWidth = () => {
  const windowGlobal = typeof window !== 'undefined'

  if(windowGlobal) {
    const [width, setWidth] = useState(window.innerWidth)

    useEffect(() => {
      const handleResize = () => setWidth(window.innerWidth)
      window.addEventListener('resize', handleResize)
      return () => {
        window.removeEventListener('resize', handleResize)
      }
    })

    return width
  }
}

export default useWindowWidth

然后在我的实际组件中,我执行以下操作:

IndexPage.Booking = () => {
  const windowWidth = useWindowWidth()

  return (
    <div className="section__booking__wrapper">
      { windowWidth <= mediaQueries.lg && <IndexPage.Cta /> }
      <div className="section__booking-bg" style={{ backgroundImage: `url(${bg})` }}>
        { windowWidth > mediaQueries.lg && <IndexPage.Cta /> }
      </div>
    </div>
  )
}

它在development中可以正常工作,但生产构建无法呈现:

<div className="section__booking-bg" style={{ backgroundImage: `url(${bg})` }}>

当在 mediaQueries.lg (1024) 下调整 window 的大小时,它会触发实际的正常行为或有条件地呈现组件的移动和桌面版本。

要仔细检查是否是因为渲染仅在resize事件上触发(它不会在development环境中加载),我也简单地从钩子console.log()中返回值并打印出来,在生产中正确加载。

生产development版本中也没有任何错误或警告。

根据@Phillip 的建议进行编辑

const useWindowWidth = () => {
  const isBrowser = typeof window !== 'undefined'
  const [width, setWidth] = useState(isBrowser ? window.innerWidth : 0)

  useEffect(() => {
    if (!isBrowser) return false

    const handleResize = () => setWidth(window.innerWidth)
    window.addEventListener('resize', handleResize)

    return () => {
      window.removeEventListener('resize', handleResize)
    }
  })

  return width
}

它现在只在你调整它的大小时工作,一次,在 mediaQueries.lg 阈值下,然后它可以在桌面和移动设备上完美地工作,但不能在加载时工作。

我遇到了与此类似的问题,还没有找到解决方案,但可以解决。 将以下内容放在渲染的开头:

if (typeof window === `undefined`) {
    return(<></>);
}

我认为正在发生的是 Gatsby 正在使用基于 window 宽度(将为 0 / 未定义)的样式构建页面。 然后它不会在页面加载后更新 DOM 中的样式,因为它认为它已经执行了该操作。 我认为这可能是 Gatsby 中的一个小错误?

无论哪种方式,以上内容都会在构建过程中将您的组件呈现为空白,迫使它在页面加载时完全遵守所有逻辑。 希望这提供了一个解决方案,尽管不是一个令人满意/完整的解释:)

我猜现在回答为时已晚,但在添加事件侦听器之前调用 handleResize 应该可以工作。 这是我用于相同目的的代码:

  useEffect(() => {
  setWidth(window.innerWidth);
  window.addEventListener("resize", () => {
    setWidth(window.innerWidth);
  });
  return () => {
    window.removeEventListener("resize", () => {});
  };
}, []);

不要在循环、条件或嵌套函数中调用 Hooks来自 React 文档

React Hooks必须每次渲染时以完全相同的顺序运行。 将您的条件移动到useEffect回调中:

useEffect(() => {
  if (typeof window === 'undefined') return;

  const handleResize = () => setWidth(window.innerWidth);
  window.addEventListener('resize', handleResize);
  return () => {
    window.removeEventListener('resize', handleResize)
  };
});

暂无
暂无

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

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