はじめに
React制のサイトを修正して本番環境にホスティングし、動作検証していると下記のエラーが表示されました。
ややこしいことに、開発環境では何も警告など表示されず本番環境でのみ出てきたのです。
もし筆者と似たような方がいればエラー文章の検索でヒットして手助けできれば幸いです。
Uncaught Error: Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
デバックするにあたって日本語の情報はいくつかあったのですが自身の現象には該当せず解決に少し苦労しました。
デバック時に目を通した日本語の記事を貼っておきますので必要に応じてチェックしてみてください!
エラーの原因
(おそらく)自身で用意したカスタムフックの2重処理が原因でした。すみませんでした。
ページ移動後のブラウザバック時に発生していた
当該エラー(#321)は、具体的にはページ遷移のクリックイベントを行った後のブラウザバック時に発生していました。ルーティングにはReact Router
を使っており、サブページからTOPページへ移動する際にLink
をクリックするとページ移動でき、ブラウザバックも問題なく行えるなど期待する挙動はしてくれるものの当該エラーが表示される、といった次第です。
試行錯誤して時間を浪費
エラー文を読むと詳しい情報が記載されたページへのリンクを促されているのでそちらで情報を確認。
(...中略)先ほど発生したエラーの全文は次のとおりです:無効なフック呼び出しです。フックは、関数コンポーネントの内部でのみ呼び出すことができます。これは、以下のいずれかの理由で発生する可能性があります: 1. Reactとレンダラー(React DOMなど)のバージョンが不一致である可能性がある 2. フックのルールを破っている可能性がある 3. 同じアプリにReactのコピーが複数ある可能性がある この問題のデバッグと修正方法のヒントについては、https://reactjs.org/link/invalid-hook-call を参照してください。
「詮索範囲が広くてなかなか絞り込めそうにないなぁ」と思いながら、とりあえずトリガーとなっているLink
まわりの検証を進めました。
この時は自分のReact Router
の設定ミスだろうと思っており、
「コード修正 → ビルド → テストサーバーへアップ」という流れで検証を進めていました。
なんとも非効率です(泣)。
しかし、原因はReact Router
の設定ミスでも何でもなく自身の作ったカスタムフック。
哀れな筆者は時間を浪費していきました……。
自身の過ちに気づく
今回話している React制のサイトでは、Context
を使用して各ページ用のStateを管理していました。
各ページ用のStateを作っている理由はtitle
やmeta
などhead
関連の情報をState別(ページ別)に用意して書き換えるようにしているためです。
TOPページ用のState変数を更新する関数をカスタムフック(以下:ChangeTopPageState
)として用意し、サブページからTOPページへ移動するリンク(Link
)のクリックイベントにそのカスタムフックを使用していました。
しかし、TOPページ(のコンポーネント)のuseEffect
内でも TOPページ用のState変数の更新関数(セッター関数) を実行していました。
この筆者の愚かな行為によって、
- 「クリックイベントでのカスタムフック(
ChangeTopPageState
)でTOPページ用のState変数を更新」 → - 「ページ遷移後のTOPページ(のレンダリング後に)同様の処理を実行」 →
- 「ブラウザバック時にState更新関連の不具合発生?」
という状況になっていたのです。
ようやく、Link
のクリックイベントに指定していたChangeTopPageState
(=自身の過ち)に気付いた筆者はクリックイベントをすべて削除。テストサーバーでエラーが表示されないことを確認し、本番環境へホスティングして同様の確認が取れました!無事解決!
解決はしたものの……「あれ?でもTOPページのuseEffect
に依存配列を記述していないし、これだけなら『State変数が単に2回変更されるだけ』なんじゃないの?」とか「ブラウザバック時にState更新関連の不具合が出ているってこと?」と思ったりもしています。
はっきりした原因を言及できず申し訳ないのですが、おそらく先述したエラー文の「2番目に該当」したのでは?と思っています。
2.フックのルールを破っている可能性がある
または、上記「筆者の愚かな行為」で説明した以下フロー
- (TOPページ用のState変数を更新するカスタムフック)
ChangeTopPageState
実行 → - TOPページ(のコンポーネント)の
useEffect
内でも同様の処理
というこれらの過程がReact
のライフサイクルに支障をきたしたのかもしれません。
まとめ
当たり前なことを言うかもですが、
React のように機能別に切り分けて組み立てていくコンポーネントベースのものは
- どこで何を使っているか(しているか)
- ソレ(State や Hook etc...)はそこで使用するのが適切なのか
- (Reactでは)再レンダリングへの考慮
といった意識・注意、コード(コンポーネント)管理が大事だなと実感しました。
ここまでお読みいただきありがとうございました。
本記事が誰かのお役に立てれば嬉しいです。