无法在生产环境中运行的Gatsby应用中基于URL参数更新JSX属性

Mik*_*ugs 3 reactjs gatsby

在生产模式下,URL参数值不能用于呈现动态属性值。相同的URL参数值可用于呈现特定的组件。

我已经建立了一个带有最小可复制示例的仓库。

https://github.com/mikepuglisi/gatsby-dynamic-attribute-bug

我们已经能够通过将参数值存储在状态中来解决此问题,但是我不明白为什么这是必要的(特别是因为它呈现了正确的div)。

相关代码(src / pages / index.js)

const IndexPage = ({location}) => {
  const params = new URLSearchParams(location.search);
  const color = params.get('color');
  return (
      <Layout>
        <SEO title="Home" />
        <h1>Hi people</h1>
        { color ?
          <p style={{color: color}}>
            I SHOULD BE THE COLOR {color} in production mode even after hitting CTRL+F5 (hard refresh)
          </p> :
          <p>
            No Color was passed. Add ?color=blue to URL and hit CTRL+F5 to ensure a hard refresh
          </p>
        }

        <div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
          <Image />
        </div>
        <Link to="/page-2/">Go to page 2</Link>
      </Layout>
    )
  }

Run Code Online (Sandbox Code Playgroud)

url参数?color=blue应该能够呈现适当的div并呈现适当的样式。div正确显示,但正确的样式不正确。问题截图

Rob*_*per 5

这个问题似乎是该hydration过程如何处理服务器渲染的React应用程序。

简短答案

您需要为颜色设置初始状态,然后通过useEffect钩子对其进行更新:

const IndexPage = ({location}) => {
  const [color, setColor] = useState();
  useEffect(() => {
    setColor(new URLSearchParams(location.search).get('color'));
  }, location)
  return (
      <Layout>
        <SEO title="Home" />
        <h1>Hi people</h1>
        { color ?
          <p style={{color: color}}>
            I SHOULD BE THE COLOR {color} in production mode even after hitting CTRL+F5 (hard referesh)
          </p> :
          <p>
            No Color was passed. Add ?color=blue to URL and hit CTRL+F5 to ensure a hard refresh
          </p>
        }

        <div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
          <Image />
        </div>
        <Link to="/page-2/">Go to page 2</Link>
      </Layout>
    )
  }
Run Code Online (Sandbox Code Playgroud)

长答案

在构建Gatsby应用进行生产时,它会使用渲染出静态HTML ReactDOMSever。当您第一次在浏览器中加载页面时,它首先加载静态HTML,然后需要启动React和hydrate您的应用程序。

在为您的应用程序充水之后,React期望您的HTML内容与客户端渲染的React应用程序的第一次渲染所呈现的内容相同。但是,对于您而言,这是不正确的。

在您的React组件的第一个渲染上,您应该style在段落元素上具有一个属性,该属性具有在URL查询参数中找到的颜色值。为页面构建静态HTML时,您style的段落元素将没有属性,因为服务器上不存在查询参数。

您可能想知道为什么文本内容在初始呈现时正确呈现了查询参数中的颜色值。这是因为该hydrate方法可以修补文本内容中的差异,但不能修补HTML属性中的差异,这就是style段落元素上的属性正在发生的情况。

从React文档获取该hydrate方法:

React期望服务器和客户端之间呈现的内容相同。它可以修补文本内容中的差异,但您应将不匹配项视为错误并加以修复。在开发模式下,React会警告水合过程中的不匹配情况。有没有保证属性的差异将在不匹配的情况下进行修补。出于性能原因,这一点很重要,因为在大多数应用中,不匹配的情况很少发生,因此验证所有标记的费用将过高。

由于初始HTML内容之间存在这种“不匹配”,您应该改为将默认值设置color为state属性,然后在首次安装组件时更新该值。这样,当您第一次在客户端上加载应用程序并且存在color查询参数时,您将能够更新安装状态以触发您的React组件的重新渲染。

资源资源