【问题标题】:DOM Attributes do not update in GatsbyDOM 属性在 Gatsby 中不更新
【发布时间】:2019-06-30 09:24:11
【问题描述】:

运行gatsby build 后,我在静态文件上遇到了一个奇怪的问题。

DOM 的属性(如 className)无法通过监听 prop 更改来更新,但 DOM 的内容(如文本或 DOM 的子项)则不能更新。

  • 仅在 gatsby-build 之后发生,也就是在 SSR 中

// 版本 1,不工作

const ThemeProvider = ({ isLight, children }) => {
  return (
    <div className={isLight ? 'light-theme' : 'dark-theme'}> // <- does not change when `isLight` updating
       <h1>{isLight ? 'light-theme' : 'dark-theme'}</h1> // <- changes when `isLight` updating
      {children}
    </div>
  )
}

// 版本 2,不工作

// still having the same issue
const ThemeProvider = ({ isLight, children }) => {
  if (isLight)
    return (
      <div className="light-theme">
       <h1>{isLight ? 'light-theme' : 'dark-theme'}</h1>
        {children}
      </div>
    )
  return (
    <div className="dark-theme">
       <h1>{isLight ? 'light-theme' : 'dark-theme'}</h1>
      {children}
    </div>
  )
}

// 版本 3,工作中

const ThemeProvider = ({ isLight, children }) => {
  if (isLight)
    return (
      <div className="light-theme">
       <h1>{isLight ? 'light-theme' : 'dark-theme'}</h1>
        {children}
      </div>
    )
  return (
    <section className="dark-theme"> // <-- change to the different DOM, everything works fine
       <h1>{isLight ? 'light-theme' : 'dark-theme'}</h1>
      {children}
    </section>
  )
}

【问题讨论】:

标签: gatsby react-ssr


【解决方案1】:

如果没有您的最小示例,很难说,但我想我可能知道您可能犯的错误。

当您在服务器上的虚拟 DOM(因此在 SSR 期间)和用于水合的虚拟 DOM(第一次在浏览器中运行)不同时,就会发生这种情况。

如果您编写如下代码,就会发生这种情况:

export default function Comp() {
  let test = 1;
  if (typeof window !== undefined) {
    test = 2;
    // usually you'd be using some browser API or
    // reading query params or something here
  }
  return <a href={test}>not updated</a>;
}

发生的情况是来自服务器的 DOM 将包含 &lt;a href=1&gt;,然后当 React/Gatsby 运行 ReactDOM.hydrate 时,一旦浏览器加载,它就会将此作为 DOM 的“真相”。在服务器上渲染。

唯一的问题是ReactDOM.hydrate 将得到&lt;a href=2&gt; 作为其结果。所以当后面运行真正的ReactDOM.render(做所谓的对账)时,虚拟DOM会看到&lt;a href=2&gt;&lt;a href=2&gt;是一回事。即使实际的 DOM 有&lt;a href=1&gt;。所以不会更新。


那么你如何解决这个问题?好吧,上面的代码有问题,你不应该这样写,你可以在副作用中这样做,比如useEffectcomponentDidMount。这样 SSR 和补水就会得到相同的结果。

对于我们上面的简单示例,它可能如下所示:

export default function Comp() {
  const [test, setTest] = useState();
  useEffect(() => { setTest(2); }, [setTest])
  return <a href={test}>updated</a>;
}

【讨论】:

  • 我找到了另一个解释相同的答案可能更好(并且只使用浏览器 API,这会导致同样的问题):stackoverflow.com/a/56403717/179978
  • 确实,这正是我遇到的问题,感谢 @odinho-velmont 提供解决方案。
猜你喜欢
  • 2011-11-04
  • 2021-03-20
  • 2019-07-14
  • 1970-01-01
  • 2011-03-30
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多