【问题标题】:Unable to update JSX attribute based on URL parameter in a Gatsby app running in production无法根据在生产中运行的 Gatsby 应用程序中的 URL 参数更新 JSX 属性
【发布时间】:2019-06-01 16:28:41
【问题描述】:

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

我已经建立了一个带有最小可重现示例的 repo。

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

我们已经能够通过将参数值存储在 state 中来解决这个问题,但我不明白为什么需要这样做(尤其是因为它呈现了正确的 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>
    )
  }

url参数?color=blue应该能够渲染合适的div并渲染合适的样式。 div 显示正确,但正确的样式不显示。Issue Screenshot

【问题讨论】:

    标签: reactjs gatsby


    【解决方案1】:

    这个问题似乎是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>
        )
      }
    

    长答案

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

    在对您的应用进行 hydration 后,React 会期望您的 HTML 内容与在客户端渲染的 React 应用的第一次渲染时渲染的内容相同。但是,在您的情况下,情况并非如此。

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

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

    来自 hydrate 方法的 React 文档:

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

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

    资源

    【讨论】:

    • 感谢您的回答,并让您更好地了解幕后实际发生的情况。很有帮助。
    • 没问题。感谢您抽出时间来设置一个带有问题示例的 repo。更容易理解发生了什么。
    • 嘿!花了大约一个小时解决类似问题。这个答案非常有帮助。谢谢!
    猜你喜欢
    • 2018-11-29
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    相关资源
    最近更新 更多