Next.js で Draft.js を使うときに起きる data-offset-key のミスマッチエラー

imatomix
2021年11月23日 13:24

エラー内容

Next.js で draft.js を使う際、ほとんどのケースで以下のワーニングがでる。
react-dom.development.js?ac89:67 Warning: Prop `data-offset-key` did not match. Server: "dhdnd-0-0" Client: "5pfru-0-0"

この状態でエディタに書き込むと以下のエラーが発生する。
Cannot read properties of undefined (reading 'getIn')

原因は最初のワーニングの通りで、サーバーサイドとクライアントサイドでdata-offset-keyの値が違うため。

ただ以下のように editorState の初期値をcreateWithContentを用いて与える場合は出ない?っぽい。なんで?
const [editorState, setEditorState] = useState(EditorState.createWithContent(convertFromRaw(JSON)))

解決方法

単純にssrを回避する。そもそもdraft.jsをssrしなければならないケースがない。と思う。
やり方は思いつく限りで2通りある。このサイトでは後者を採用している。

useEffectを使うパターン

描画のタイミングをマウント後にすることで、ssrを回避する。
import { useEffect, useState } from 'react' import {Editor, EditorState} from 'draft-js' const DraftEditor = () => { const [editorState, setEditorState] = useState<EditorState>(null) // マウント後に editorState を作成 useEffect(() => { setEditorState(EditorState.createEmpty()) }, []) return ( <> {editorState && ( // マウント後に描画 <Editor editorKey="editor" editorState={editorState} onChange={setEditorState} /> )} </> ) }

Dynamic import を使うパターン

draft.jsを使用しているコンポーネントを Dynamic import で読み込む。その際にオプションでssrfalse にして、サーバーサイドレンダリングを無効にする。
import dynamic from 'next/dynamic' const DraftEditor = dynamic( () => import('@/components/molecules/DraftEditor'), { ssr: false } // ssr が無効になる )


First Load JS のサイズを減らす意味でも Dynamic import で ssr を無効化するほうがいいと思う。