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

时间:2019-05-31 16:36:24

标签: 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>
    )
  }

url参数?color=blue应该能够呈现适当的div并呈现适当的样式。 div可以正确显示,但样式不能正确显示。Issue Screenshot

1 个答案:

答案 0 :(得分:2)

这个问题似乎是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应用。

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

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

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

从React文档中获取hydrate方法:

  

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

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

资源