no match between SSR'ed Dom structure and rehydrated
here is code of my page:
render() {
const {
query: { random_key }
} = this.props
return (
<KeepAlive id={random_key} name={`p/${random_key}`}>
<ScrollPosition>
<Product {...this.props} />
</ScrollPosition>
</KeepAlive>
)
}
Rehydrated page must matches the original SSR'ed page otherwise react will recreate DOM and as a side effect core web vitals metrics like LCP will be measured after client-side rehydration.
this is console error of this problem:

implementation environment: reactjs: 16.13.1 nextjs: 9.4.4 react-activation: 0.4.2
I also checked react-activation version 0.5.5 and the problem exists.
I have almost no experience with React SSR hydrate, so I just made a simple SSR compatibility in react-activation
The implementation of react-activation determines that it may not be able to guarantee that the content rendered by the client and server is consistent when the application is initialized.
Do you have any idea on this issue?
please read this post: https://joshwcomeau.com/react/the-perils-of-rehydration/ you should remove some stochastic conditions in the code.
same issue on react-keep-alive: https://github.com/StructureBuilder/react-keep-alive/pull/85
Hi @CJY0208, can you please explain briefly how you added SSR to react-keep-alive library. I have to fix this issue if you write some help about the implementation.
I confirm this is an issue, still forced to use react-keep-alive due to this issue.
I confirm this is an issue, still forced to use react-keep-alive due to this issue.
Hi @AlexSapoznikov I have decided to not use react-keep-alive and i have used another better solution to keep my pages alive in react.
I confirm this is an issue, still forced to use react-keep-alive due to this issue.
Hi @AlexSapoznikov I have decided to not use react-keep-alive and i have used another better solution to keep my pages alive in react.
Hi @khanbaba So what are you using, if I may ask?
I confirm this is an issue, still forced to use react-keep-alive due to this issue.
Hi @AlexSapoznikov I have decided to not use react-keep-alive and i have used another better solution to keep my pages alive in react.
Hi @khanbaba So what are you using, if I may ask?
read the solution here: https://stackoverflow.com/questions/59124463/nextjs-how-to-not-unmount-previous-page-when-going-to-next-page-to-keep-state
I confirm this is an issue, still forced to use react-keep-alive due to this issue.
Hi @AlexSapoznikov I have decided to not use react-keep-alive and i have used another better solution to keep my pages alive in react.
Hi @khanbaba So what are you using, if I may ask?
read the solution here: https://stackoverflow.com/questions/59124463/nextjs-how-to-not-unmount-previous-page-when-going-to-next-page-to-keep-state
Thanks! Will look into it.
有进展吗? @CJY0208
@CJY0208 cc
出问题应该是这里,在 server 端和 client 端分别使用了不同的组件进行渲染,导致了出现节点匹配不一致的问题。 其实这里不需要环境的判断,直接使用 expandKeepAlive(withActivation(KeepAlive)) 在双端渲染也是 ok 的
https://github.com/CJY0208/react-activation/blob/8c3161ec1f01ed06f344620a3c156ac2a1037aae/src/core/KeepAlive.js#L271
我 debug 到这里的时候大概发现的是,react 在进行 hydrate 的时候,就出来了节点 mismatch 的情况了
复现路径:
可以在 feat/keep-alive-plugin 这个分支上,执行 npm run setup 脚本安装依赖后,然后 cd example/with-keep-alive 执行 npm start 即可复现问题了
参考:https://github.com/facebook/react/issues/24384
意思就是 keep alive 组件的 ssr 和 csr 逻辑不一致所以报错了
但现在面临一个问题,keep alive 的原理本来就是先渲染到别处再 dom 移回来的
ssr 没有 dom 所以是直接渲染的
如果要 ssr 也和 csr 保持一致,那可能导致 ssr 的产物里,KeepAlive 内部的视图显示不出来
意思就是 keep alive 组件的 ssr 和 csr 逻辑不一致所以报错了
但现在面临一个问题,keep alive 的原理本来就是先渲染到别处再 dom 移回来的
ssr 没有 dom 所以是直接渲染的
如果要 ssr 也和 csr 保持一致,那可能导致 ssr 的产物里,KeepAlive 内部的视图显示不出来
ssr 只关心第一次渲染的结果,后面视图更新都是由 csr 承接的。你现在只需要保证 ssr KeepAlive 内的内容出来就行,事实上是可以的。
现在可见的修复措施,产生的结果可能是 ssr 首屏的内容里,KeepAlive 标签包裹的部分会是空白的,这个感觉是不可接受的吧
现在可见的修复措施,产生的结果可能是 ssr 首屏的内容里,KeepAlive 标签包裹的部分会是空白的,这个感觉是不可接受的吧
什么情况下是空白的?目前我用的时候没有空白
Not a great solution, but if you're willing to sacrifice an extra re-render here's a hack for NextJS.
Create a KeepAlive wrapper component:
import { KeepAlive as _KeepAlive } from "react-activation";
import React, { FC, ReactNode, useEffect, useState } from "react";
export interface KeepAliveProps {
children: ReactNode;
}
const KeepAlive: FC<KeepAliveProps> = ({ children }: KeepAliveProps) => {
const [keepAliveChildren, setKeepAliveChildren] = useState(<>{children}</>);
useEffect(() => {
setKeepAliveChildren(<_KeepAlive saveScrollPosition="screen">{children}</_KeepAlive>);
}, []);
return <>{keepAliveChildren}</>;
};
export default KeepAlive;
and then use it like this:
import KeepAlive from "@client/components/common/shared/keep-alive";
import React, { FC } from "react";
const IndexPage: FC = () => {
return (
<KeepAlive>
<div>Hello World!</div>
</KeepAlive>
);
};
export default IndexPage;
Not a great solution, but if you're willing to sacrifice an extra re-render here's a hack for NextJS.
Create a KeepAlive wrapper component:
import { KeepAlive as _KeepAlive } from "react-activation"; import React, { FC, ReactNode, useEffect, useState } from "react"; export interface KeepAliveProps { children: ReactNode; } const KeepAlive: FC<KeepAliveProps> = ({ children }: KeepAliveProps) => { const [keepAliveChildren, setKeepAliveChildren] = useState(<>{children}</>); useEffect(() => { setKeepAliveChildren(<_KeepAlive saveScrollPosition="screen">{children}</_KeepAlive>); }, []); return <>{keepAliveChildren}</>; }; export default KeepAlive;and then use it like this:
import KeepAlive from "@client/components/common/shared/keep-alive"; import React, { FC } from "react"; const IndexPage: FC = () => { return ( <KeepAlive> <div>Hello World!</div> </KeepAlive> ); }; export default IndexPage;
The new Problem.
app-index.js:32 Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the ProviderBridge component.