2

我正在使用 react-static 生成一个静态网站。使用新useLayoutEffect钩子 API,我在静态渲染阶段收到此警告(与服务器端渲染相同的 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]
  )

什么是正确的方法?

4

2 回答 2

0

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

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 部分,而这正是警告的重点。

于 2019-03-05T17:44:49.633 回答
0

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

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

您也可以尝试使用requestAnimationFrame函数而不是 Context:

useEffect(() => { 
  window.requestAnimationFrame(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible';
  });
}, [isLoading]);
于 2019-03-05T10:30:50.863 回答