background
I was trying to write the Renderer of the article table by myself yesterday. After a certain save, suddenly the following error appeared:
Find problems
official documentation
First, check the official description of the problem according to the error log:
react-hydration-error | Next.js
Officials blamed the problem on two possible reasons:
- In the rendering process, the server side and the browser side are judged, resulting in different rendering results. Common questions are:
- Judging whether the window exists outside the React Hook and affecting the return result
- The possible reasons that are not officially mentioned are: environment variables available only on the server side are used during the rendering process, such as
process.env
- The css-in-js library is used, but the corresponding plug-ins are not set, such as swc and Babel that come with react. For example use:
- Styled Components
- Emotion
Obviously, my case is not among them: I am triggering this error when the environment has not changed, the code has changed.
Framework bug
So it is suspected that the bug of Next.JS and React 18 is triggered. After some searching, I found that there is indeed a related GitHub Issue, but the trigger condition is to embed < in the
- which doesn't work in my case either. After that, I also tried to close swcMinify of Next.JS and upgrade to Canary, but the problem is still not solved.<p>
element div>
other possibilities
- CDN server: CDN servers such as Cloudflare will cache some static scripts and json, which will also cause inconsistent rendering between the server and the client. You can try clearing the CDN cache
- The <title> component has multiple children: for example,
<span>Hello {world} foo</span>
should not be used, Instead, use<span>{`Hello ${world} foo`}</span>
. See GitHub Discussion: https://github.com/vercel/next.js/discussions/38256.
code error
In the end, you can only go back to the error itself and turn your attention back to the code.
After trying to annotate the components one by one, I located the problematic component and its code. One of them is:
...
const {withHeadings, content} = props.data;
if (withHeadings) {
let headingData = content.shift();
heading = (<thead>
<tr>
{
headingData.map((cell, index) => {
return <th key={index}>{cell}</th>
})
}
</tr>
</thead>
);
}
...
Those who may have experience have seen the problem:
Since JS does not clearly distinguish between pass-by-value or pass-by-reference (shared call) when passing parameters, I made a mistake here: by destructuring the declaration, I changed it from props.data
got content
, and called content.shift( )
Original parameter changed.
Here, although the new array content
is taken out through destructuring declaration, it is still the original Shared calls for arrays in -code">props
objects. It was modifying the original incoming parameters that caused my problem.
Let's review the rendering process of Next.js first:
- Next.js first pre-renders on the server (Server Side Generation) and generates static HTML and JSON.
- The JSON will then be passed to the browser and rendered again (ie "Hydration").
In step 1, the content array is changed by content.shift()
in the rendering process and becomes a new slice< /b> (content.slice[1, content.length]
), the JSON generated subsequently is a slice of content; when performing the steps 2. When the browser uses JSON for Hydration, it is not the original content. Therefore, after comparing the rendering results, the framework will naturally find that one less line of content is rendered, and throw the Hydration failed
error.
fix the problem
In summary, the correct code should copy the original array and operate on the new array:
...
const {withHeadings} = props.data;
if (withHeadings) {
const content = [...data.content]; //复制数组的内容
let headingData = content.shift();
...
}
...
Summarize
When writing render functions, care should be taken not to modify props
- not only the props itself, but also the references he holds in the properties .
Comments