运行gatsby build后,我在静态文件上出现了一个奇怪的问题。
DOM的属性(如className)不能通过监听道具更改来更新,但不能通过DOM的内容(如文本或DOM的子元素)进行更新。
// Verison 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>
)
}// Verison 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>
)
}// Verison 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>
)
}发布于 2020-01-27 14:40:55
很难说没有你的最小的例子,但我想我可能知道你可能的错误。
当服务器上的虚拟-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将包含<a href=1>,然后当React/Gatsby在浏览器加载后运行ReactDOM.hydrate时,它会将其用作DOM在服务器上呈现时的“真相”。
唯一的问题是ReactDOM.hydrate将得到<a href=2>作为其结果。因此,当以后运行真正的ReactDOM.render (执行所谓的协调)时,虚拟DOM将看到<a href=2>和<a href=2>是相同的。即使实际的DOM有<a href=1>。这样就不会更新了。
那你怎么解决这个问题?嗯,上面的代码是错误的,你不应该那样写它,你可以在副作用中这样做,比如useEffect或componentDidMount。这样SSR和再水合物就会得到同样的结果。
对于上面的简单示例,它可能如下所示:
export default function Comp() {
const [test, setTest] = useState();
useEffect(() => { setTest(2); }, [setTest])
return <a href={test}>updated</a>;
}https://stackoverflow.com/questions/56823750
复制相似问题