Gatsbyで作っているブログで今までずっとDevTools上に下記のようなエラーが出ていた
内容的にはhydrationエラーだよというもの
react-dom.production.min.js:131 Uncaught Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at sa (react-dom.production.min.js:131:159) at xi (react-dom.production.min.js:293:379) at bs (react-dom.production.min.js:280:389) at vs (react-dom.production.min.js:280:320) at gs (react-dom.production.min.js:280:180) at ls (react-dom.production.min.js:268:209) at S (scheduler.production.min.js:13:203) at MessagePort.T (scheduler.production.min.js:14:128) Uncaught Error: Minified React error #423; visit https://reactjs.org/docs/error-decoder.html?invariant=423 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at xi (react-dom.production.min.js:293:39) at bs (react-dom.production.min.js:280:389) at vs (react-dom.production.min.js:280:320) at gs (react-dom.production.min.js:280:180) at as (react-dom.production.min.js:271:88) at ls (react-dom.production.min.js:268:429) at S (scheduler.production.min.js:13:203) at MessagePort.T (scheduler.production.min.js:14:128)
結構長いこと放置していたが、ふとGatsbyのドキュメントを読んでいたら次のページを見つけた
一部抜粋すると
注意: wrapPageElementとwrapRootElementのAPIは、ブラウザとサーバーサイドレンダリング(SSR)の両方のAPIに存在します。一般的には、gatsby-ssr.jsとgatsby-browser.jsの両方に同じコンポーネントを実装して、SSRで生成されたページがブラウザでハイドレートされた後も同じであるようにする必要があります。
しれっと両方にwrapPageElement
,wrapRootElement
を使う場合はbrowser,ssr両方に実装しようと書いてある
Hydrationエラーはそういうものだよねっていうのは調べたので知ってはいたが…
たしかに同じコンポーネント実装すれば同じになるよねという感じ
型の対応
TypeScriptで書いているので型定義もしてあげないといけないが最初うまく行かなかった
同じ実装ということで共通のコンポーネントを書いてそれをgatsby-browser.ts
,gatsby-ssr.ts
から読めるようにする
- gatsby-browser.tsx
export { wrapPageElement } from "./src/wrap-page-element"
- gatsby-ssr.tsx
export { wrapPageElement } from "./src/wrap-page-element"
このような感じ
wrapPageElement
に用意されている型は
browser
GatsbyBrowser["wrapPageElement"]
ssr
GatsbySSR["wrapPageElement"]
のようだったが、次のようにすると引数がanyになってしまい困る
import type { GatsbyBrowser, GatsbySSR, WrapPageElementNodeArgs } from "gatsby" type WrapPageElement = GatsbyBrowser["wrapPageElement"] | GatsbySSR["wrapPageElement"] export const wrapPageElement: WrapPageElement = ({ element, props }) => { return <Layout {...props}>{element}</Layout> }
いくつかGitHubを探してみたら受け取る引数の型定義をWrapPageElementNodeArgs
にしているコードを見つけた
たしかにBrowser、Serverともに結局引数はこの型になるんだし型的には問題ないはず
ということで、現在のところ下記のような形に落ち着いた
- src/wrap-page-element.tsx
// custom typefaces import "typeface-montserrat" import "typeface-merriweather" import "prismjs/themes/prism-coy.css" import "prismjs/plugins/line-numbers/prism-line-numbers.css" import "./styles.scss" import { default as React } from "react" import Layout from "./components/layout" import type { GatsbyBrowser, GatsbySSR, WrapPageElementNodeArgs } from "gatsby" type WrapPageElement = GatsbyBrowser["wrapPageElement"] | GatsbySSR["wrapPageElement"] export const wrapPageElement: WrapPageElement = ({ element, props }: WrapPageElementNodeArgs) => { return <Layout {...props}>{element}</Layout> }
これでHydrationエラーは消えた
最初から一通りドキュメント読んだほうがよいやつ…