LoginSignup
0
0

More than 1 year has passed since last update.

【Next.js】Warning: Prop xxx did not match. Server: aaa Client: bbbへの対応

Posted at

やろうとしたこと

配列をシャッフルしてから表示しようとしました。

ざっくりと下のような感じです。

Sample.tsx
import { useState } from 'react'

export const Sample = () => {

    const [numberArray, setNumberArray] = useState<number[]>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    const shuffleArray = () => { 配列をシャッフルする処理 };    

    shuffleArray(numberArray);
    setNumberArray([...numberArray])

    return (
        <div>
            {numberArray.map((number, index) => {
                <p key={index}>{number}</p>
            })}
        </div>
    )
}

エラー

Warning: Prop xxx did not match. Server: aaa Client: bbb

という内容のエラーが表示されました。

原因

ReactではSSRした内容とCSRした内容を比較し、もし同じ場合はSSRした値をそのまま利用する(これをhydorateという)。
上記では配列をシャッフルしているため、SSRした内容とCSRした内容が異なっていたことが原因。

ReactDOM.hydrate()はReactDOMServer、つまりサーバサイドで作成されたHTMLをクライアントサイドで再利用するメソッドです。
ReactDOM.hydrate()はサーバサイドとクライアントサイドのレンダリング結果が一致することを期待します。
結果が一致する場合はクライアントサイドでのレンダリングをスキップ、不一致の場合はクライアントサイドで再度レンダリングをします。

【Next.js】Hydration時にReact.hydrate()による警告が発生するケースとその解決方法

↓ こんな感じ

SSRで生成された配列: [1, 5, 7, 3, 4, 0, 2, 8, 9, 6]

CSRで生成された配列: [5, 9, 2, 3, 1, 8, 0, 4, 6, 9]

対処

useEffect内で処理を実行する。

Sample.tsx
import { useState, useEffect } from 'react'

export const Sample = () => {

    const [numberArray, setNumberArray] = useState<number[]>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    const shuffleArray = () => { 配列をシャッフルする処理 };    

    useEffect(() => {
        shuffleArray(numberArray);
        setNumberArray([...numberArray])
    },[])
    

    return (
        <div>
            {numberArray.map((number, index) => {
                <p key={index}>{number}</p>
            })}
        </div>
    )
}

流れとしては下のようになります

エラー時

初期状態: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
↓
SSR: [1, 5, 7, 3, 4, 0, 2, 8, 9, 6] // シャッフルされた
↓
CSR(hydration実行): [5, 9, 2, 3, 1, 8, 0, 4, 6, 9] // SSRの結果と異なる
↓
Warning(一応CSRの内容で画面描画はされます。)

useEffect使用時

初期状態: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
↓
SSR: [1, 5, 7, 3, 4, 0, 2, 8, 9, 6] // シャッフルされた
↓
CSR(hydration実行): [5, 9, 2, 3, 1, 8, 0, 4, 6, 9] // SSRの結果と異なる
↓
useEffectが呼び出され、再レンダリングされる。: [3, 6, 7, 1, 0, 9, 2, 5, 4, 8] // 別の配列が生成される
↓
画面描画:[3, 6, 7, 1, 0, 9, 2, 5, 4, 8]

ただし、公式によると、この方法はパフォーマンスの低下を招くので注意してくださいとのことです。

このアプローチでは 2 回レンダーが発生することによりコンポーネントのパフォーマンスが低下しますので、注意して使用してください。

hydrate()

参考

React Hydration Error

【図解】Next.jsのSSRが画面反映されるまでの具体的な流れ

【Next.js】Hydration時にReact.hydrate()による警告が発生するケースとその解決方法

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0