React18からのcreateRootでElement type is invalidのエラーは依存関係の解決に失敗したときにも出る
TL;DR
- "Element type is invalid, expected a string (for built-in components) or a class/function but got ..." というエラー
- 素直に読み取ると
createRoot(container).render(<App />)
などにおけるApp
の型がstring or class/function じゃねーよって言われてると感じる - しかし間違いなく
App
は function(or無名関数)なんだが???? となり迷宮にハマる - 実際には
App
コンポーネントの中の依存関係の解決に失敗しているのが原因だったりする- たとえば素のReactだけを利用しているのではなく外部のコンポーネントやライブラリを参照しているときなど
- たとえば「Webpackやだなー」とかでRollupやParcelとかの別のビルドツールを使ってるときになどにbundleファイルの作成や読み込みに失敗してるときなど
意味不明すぎて8時間近くネットの海を漂ったあげくChatGPTさんに相談してみたら頼りになるアドバイスをくれた
Bardに最初に相談したけど大した答えをくれなかった。
「エラーメッセージから、App という名前のクラスが存在しないことが原因でエラーが発生していることがわかります。」
とかいうけど、あるんだつってんの。
「申し訳ありませんが、エラーが解消しない原因がわかりません。別のエラーメッセージを提供していただければ、調査してみます。」
とか言い出して、ダメだこりゃって感じ。
新しい情報だからChatGPTくん苦手かも……と思いながら聞いてみたら
「以下のように App オブジェクトが正しく構造化されているか、またはそれが含むサブコンポーネントが正しくエクスポートされているかを確認してみてください。」
console.log(App);
と言い出したので Google Chrome の console で App
がグローバルに存在することを確認した上で、
「オブジェクトとして存在し、BackgroundやControlsなどのサブコンポーネントを含んでいることが確認できました」と再度きいてみると
「問題は異なる箇所にあるかもしれません。そのエラーメッセージは通常、Reactが予期せずにundefinedやnullのような無効な要素をレンダリングしようとしたときに表示されます。もしくは、要素がReactコンポーネントとして適切にエクスポートやインポートされていない場合にも表示されます。
問題の切り分けのため、以下の手順をお試しください:
App コンポーネントを単純なHTML要素に書き換えてみてください。エラーが出なければ、問題は App コンポーネントである可能性が高いです。例:...」
と言ってくれた。な、なるほど確かに…… 頼りになるぜChatGPT兄貴。
問題の切り分けは、エラー解消の基礎ですね。すいません。
最小限の単位でテストしてみる
const App = () => {
return React.createElement("div", null, "Hello, World!");
};
export default App;
import { createRoot } from 'react-dom/client';
import App from 'App'
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
これでエラーが出続けるかどうかみてみる
- エラーが解消した
- 実は
render
に渡してるものの型が違うわけではないので、依存関係の解決などを疑ってみましょう
- 実は
- エラーが解消しない
- 今回の記事で僕がハマった現象ではないようです、他の原因を探してみてください……
参考
- How to Upgrade to React 18 | React
- React18からはレンダリングにcreateRootを使おう | matsuyama |zenn
- 今更の React 18 ReactDOM の render の使い方が変わった | かもメモ
- (React) Element type is invalid, expected a string (for built-in components) or a class/function but got | Borislav Hadzhiev
- エラーが意味不明すぎてrenderに渡すべき型は何が正しいのかとか調べてたときに見つけたわかりやすい記事
- TypeScript: ReactNode型とReactElement型とReactChild型 | dackdive | はてなブログ
Discussion