首页 > 解决方案 > React 正在渲染一个组件的一部分和另一个组件的一部分

问题描述

我正在构建的 Gatsby 网站中发生了一些非常奇怪的事情。我觉得这可能是一个我不知道的奇怪的 React 错误。太奇怪了,我可能很难描述它,但这里有:

我想将我的联系人页面上的不同页脚组件呈现给我网站的其余部分。组件相似但不相同。

我正在使用这样的代码:

{
!isContact ? // this is a useState state 
<Footer /> :
<FooterContact />
}

错误是,有时当isContact为真时,呈现的 html 由前几行Footer组件组成,然后是我的组件的其余FooterContact部分。即我得到:

<footer>                    // this is from the Footer component
  <div class="inner">       // this is from the Footer component
    <h1>Contact footer</h1> // this is from the FooterContact component
    <p>Lorem Ipsum</p>      // this is from the FooterContact component
  </div>
</footer>

发生这种情况的条件是:

有没有人经历过这样的事情?

关于我可以尝试调试的任何建议?在过去的几个小时里,我一直在尝试一些东西,但我觉得我离弄清楚发生了什么更近了。

谢谢

标签: javascriptreactjs

解决方案


当服务器端呈现的 HTML 和客户端呈现的初始影子 DOM 之间存在差异时,就会发生这种情况。这会在 React 尝试将组件渲染的 DOM 输出与实时 HTML DOM 对齐的水合过程中导致问题。

根据取决于环境或渲染上下文的表达式,查找您正在有条件地渲染的代码区域。具体来说,您正在寻找任何可能导致在初始渲染期间呈现不同条件分支的表达式。

例如,这是一个问题:

const ExampleOfProblematicCode = () => {
  const isClientSide = typeof window !== "undefined"

  return isClientSide ? <div>Hello!</div> : null
}

相反,等到useEffect钩子有机会执行并更改状态以提示重新渲染,然后再更改输出客户端:

const ExampleOfGoodPractice = () => {
  const [isLoaded, setIsLoaded] = useState(false)

  useEffect(() => { setIsLoaded(true) }, [])

  return isLoaded ? <div>Hello!</div> : null
}

这将在初始渲染期间渲染相同的输出,之后 React 将运行导致生成并渲染备用条件分支的useEffect钩子。isLoadedtrue


编辑:澄清一下,当存在水合不匹配时,这种行为正是预期的:

发生这种情况的条件是:

  1. 它只发生在实时服务器上。
  2. 只有当我“刷新”联系页面时才会发生这种情况。如果我通过另一个页面的链接前往那里,FooterContact 组件会呈现良好。

这是因为初始加载是唯一包含预渲染 HTML 的加载。之后,React 水合物和 Gatsby 通过加载所需的 webpack 块和 page-data.json 文件来处理客户端导航,以在客户端呈现后续页面。


推荐阅读