渲染静态网站时的条件挂钩

Posted

技术标签:

【中文标题】渲染静态网站时的条件挂钩【英文标题】:Conditional hooks when rendering static website 【发布时间】:2019-07-26 18:53:18 【问题描述】:

我正在使用 react-static 来生成静态网站。使用来自the new hook API 的useLayoutEffect,我在静态渲染阶段收到此警告(与服务器端渲染相同的API):

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format.
  This will lead to a mismatch between the initial, non-hydrated UI and th  e intended UI.
  To avoid this, useLayoutEffect should only be used in components that render exclusively on the client.

这当然是有道理的。 但是,当确定不会出现任何不匹配时,消除此警告的好选择是什么?

在我的布局效果中,我只是在 body 标签中添加了一点 CSS,因此在客户端的水合阶段不会出现任何不匹配(因为 body 不是 React 的业务)。

React 强烈禁止使用条件挂钩,但在那种 非常 特定的情况下,做类似这样的事情是否有意义:

if(typeof window !== 'undefined')
  useLayoutEffect(() => 
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    ,
    [loading]
  )

正确的方法是什么?

【问题讨论】:

【参考方案1】:

我认为您应该使用 Context 将值“隐藏/可见”传递给其他组件。在这种情况下,呈现所有页面的包装器的组件。

useEffect(() =>  
  fnSetContextValue(isLoading ? 'hidden' : 'visible') 
, [isLoading]);

您也可以尝试使用requestAnimationFrame 函数而不是上下文:

useEffect(() =>  
  window.requestAnimationFrame(() => 
      document.body.style.overflowY = loading ? 'hidden' : 'visible';
  );
, [isLoading]);

【讨论】:

使用useEffect 而不是useLayoutEffect 确实不会触发警告,但是我失去了useLayoutEffect 的同步方面。 哦,我在帖子中写了useEffect,是的。已更正。我的意思是useLayoutEffect【参考方案2】:

好的,这就是我想出的不太脏的解决方案。而不是实施天真的解决方案,即。一个条件钩子:

const Layout = () => 
  const [loading, setLoading] = useState()

  if(typeof window !== 'undefined')
    useLayoutEffect(() => 
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    , [loading])

  return ( ... )


export default Layout

在很多情况下感觉很脏,反模式,语义错误和无用(为什么在每次渲染时检查window?),我只是将条件放在组件之外:

const LayoutView = ( loading, setLoading ) => ( ... )

const Layout = (typeof window === 'undefined') ? (
  () => 
    const [loading, setLoading] = useState()
    return <LayoutView loading=loading setLoading=setLoading/>
  
): (
  () => 
    const [loading, setLoading] = useState()
    useLayoutEffect(() => 
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    , [loading])
    return <LayoutView loading=loading setLoading=setLoading/>
  
)

export default Layout

但请注意,这只是因为我的布局效果不会影响 React 的 DOM 部分,而这正是警告的重点。

【讨论】:

以上是关于渲染静态网站时的条件挂钩的主要内容,如果未能解决你的问题,请参考以下文章

在没有服务器后端的静态 HTML/JS 网站上完成 PayPal 付款。如何渲染完成的支付页面?

通过 github.io 渲染静态网页不起作用 - 对于使用 gatsby 创建的网站/从 github repo 托管在 netlify 上的网站

Nuxtpress - Node.js 动态网站静态化之路

前端模板网站是动态的还是静态的?

快来用 Nuxt 开发静态网站

我的网站获取静态文件时遇到问题