React・つまずきを自力で直す

エラーの読み方と開発者ツール

画面が真っ白、なぜか同じ数字が出る、押しても何も起きない——Reactでよく出るエラーを5つに分けて、メッセージのどこを読めば原因にたどりつけるかを整理します。React DevToolsでpropsとstateを目で見る方法も扱います。

ここまでで、state・イベント・一覧がそろいました。Reactでエラーが出る材料も、ちょうど出そろったということです。

この回は新しい機能を作りません。出たエラーを自分で直せるようにするための回です。

エラーは3か所に出る

まず、どこを見ればいいのかを決めておきます。

場所何が出るか
ブラウザの赤い画面(Viteのオーバーレイ)書き方の間違い(構文エラー)。ファイル名と行番号つき
ブラウザのコンソール動かしてみて初めて分かるエラー・警告
ターミナルnpm run devを動かしている画面)ビルド側のエラー。オーバーレイと同じ内容が多い

上から順に見るのが早道です。赤い画面が出ているなら、コンソールを見る前にそこを読んでください。

Viteの赤いエラー画面。「Expected corresponding JSX closing tag for ‘p’」というメッセージと、該当する行のコードが番号つきで表示されている
</p>を書き忘れたときの画面。「どのファイルの何行目か」「何を期待していたか」が全部書いてあります

この画面は書いてあるとおりに直せば直ります。上の例なら「src/App.jsxの80行目、<p>に対応する閉じタグが無い」です。

よく出るエラー5つ

Objects are not valid as a React child

オブジェクトをそのまま画面に出そうとしたときのエラーです。

{bird}              {/* ✕ オブジェクトごと出そうとしている */}
{bird.name}         {/* ○ 中の値を指定する */}

{}の中に入れていいのは文字列・数値・JSX・その配列だけです。オブジェクトの中身を確認したいときは、いったんconsole.log(bird)で見るか、{JSON.stringify(bird)}で文字列にします。

Cannot read properties of undefined (reading 'map')

まだ届いていないデータに対してmapを呼んだときに出ます。useEffectで読みこむ前の一瞬に起きがちです。

const [birds, setBirds] = useState()      // ✕ 初期値がない = undefined
const [birds, setBirds] = useState([])    // ○ 空の配列から始める

配列のstateは必ず[]から始める——これだけでほとんど防げます。読みこみ中の表示(isLoading)を出すのも同じ理由です。

Each child in a list should have a unique "key" prop

一覧にkeyが無いという警告です。画面は出るので放置しがちですが、並べかえや削除をしたときに状態が別の行へ移る原因になります。

{birds.map((bird) => <BirdCard key={bird.id} bird={bird} />)}
React配列から一覧を作る(mapとkey)keyが何をしているのか、なぜindexではだめなのかはこの回に

Too many re-renders

描画のたびに状態を更新していて、止まらなくなっています。 原因はたいてい2つです。

<button onClick={handleClick()}>       {/* ✕ 描画時に実行されてしまう */}
<button onClick={handleClick}>         {/* ○ 関数を渡す */}
useEffect(() => { setCount(count + 1) })        {/* ✕ 依存配列がない */}
useEffect(() => { setCount(count + 1) }, [])    {/* ○ 最初の1回だけ */}

Rendered more hooks than during the previous render

Hooksを呼ぶ場所のルールを破っています。 ifの中や早期returnより後ろにuseStateuseEffectを置くと出ます。

if (!bird) return null
const [liked, setLiked] = useState(false)   // ✕ returnより後ろ

Hooksはコンポーネントの先頭にまとめて書く。 これだけです。

エラーが出ないのに動かないとき

いちばん困るのがこれです。順番に確かめます。

  1. そもそも呼ばれているか——処理の1行目にconsole.log('ここまで来た')を置く
  2. 値は思ったとおりか——console.log(keyword, shownBirds.length)のように複数まとめて出す
  3. 画面とデータがずれていないか——次のReact DevToolsで見る
べんりワザエラーが出ても、あわてないエラーメッセージの読み方そのもの(英語の読み下し方・検索のしかた)はこちらにまとめてあります

React DevToolsでpropsとstateを見る

console.logを挟まなくても、いまのpropsとstateをそのまま見られる道具があります。React公式が配っているブラウザの拡張機能です。

入れると開発者ツールにComponentsProfilerの2つのタブが増えます。使うのはほぼComponentsだけです。

  • 左にコンポーネントの木AppBirdCard …)が出る
  • 部品を選ぶと、右にpropshooks(state)の中身が出る
  • 値はその場で書きかえて試せる

「propsが渡っていないのか、渡っているけど表示が間違っているのか」が一目で分かるので、切り分けの時間が激減します

ja.react.dev外部サイトReact Developer Tools – React公式の案内ページ。Chrome・Firefox・Edgeの拡張機能へのリンクがまとまっていますべんりワザ開発者ツールの使い方入門ブラウザの開発者ツール自体の使い方(要素の確認・コンソール・ネットワーク)はこちら

直すときの順番

最後に、詰まったときの手順をまとめておきます。

  1. 赤い画面が出ていたら、そこだけ読む(ファイル名と行番号がある)
  2. コンソールの一番上のエラーを読む(下のほうは巻き添えのことが多い)
  3. エラー文をそのまま検索する(自分のファイル名や変数名は消して検索する)
  4. 直前に書いた数行を消してみる(動けば、その数行が原因)
  5. React DevToolsでpropsとstateを見る

このレッスンのまとめ

  1. エラーは赤い画面 → コンソール → ターミナルの順に見る
  2. 英語は全部読まない。何が・どうなっている・どこでの3つだけ拾う
  3. Objects are not valid…オブジェクトをそのまま出したとき
  4. Cannot read properties of undefined配列stateの初期値[]忘れが定番
  5. Too many re-renders括弧つきで渡した依存配列忘れ
  6. Rendered more hooks…Hooksを先頭に書いていない
  7. React DevToolsでpropsとstateを直接見ると、切り分けが一気に速くなる

次の章からは、データをアプリの外に出します。まずはuseEffectで読みこむところから。

やってみよう:わざと壊して、直す

エラー画面に慣れておくと、本番で焦らなくなります。わざと壊して、元に戻す練習をします。

  1. src/App.jsx</p>をひとつ消して保存し、赤い画面のファイル名と行番号を確認する
  2. 元に戻して、画面が復活することを確認する
  3. <BirdCard key={bird.id} … />keyを消して保存し、コンソールの警告を確認する(画面は出たままのはず)
  4. keyを戻す
  5. React DevToolsを入れて、ComponentsタブでBirdCardを1つ選び、birdのpropsとisFavoriteの値を見る
Viteの赤いエラー画面に、閉じタグが無いという指摘と該当行が表示されている
壊したときに出る画面。ここに答えが書いてあると分かっていれば、もうこわくありません

エラーを出す練習は、動くコードを書く練習と同じくらい役に立ちます。

よくある質問

Reactで画面が真っ白になったときは何を見ればいいですか?
まずブラウザの画面に出る赤いエラー画面(Viteのオーバーレイ)、次にブラウザのコンソール、最後に開発サーバーを動かしているターミナルの3か所です。多くの場合、最初のオーバーレイにファイル名と行番号が出ています。
「Objects are not valid as a React child」はどういう意味ですか?
オブジェクトをそのまま画面に出そうとしたという意味です。{bird}のようにオブジェクトごと波かっこに入れると出ます。{bird.name}のように中の値を指定するか、配列ならmapで要素に変換してください。
「Too many re-renders」が出ました
描画のたびに状態を更新していて、更新→再描画→更新…が止まらなくなっています。onClick={handleClick()}のように括弧を付けて渡していないか、useEffectの依存配列を書き忘れていないかを見てください。
React DevToolsは必要ですか?
必須ではありませんが、propsとstateの中身をその場で見られるので、原因の切り分けが一気に速くなります。ブラウザの拡張機能として無料で入れられます。