🐻‍❄️

Next.jsでTableタグを使ったら謎のエラーに苦しめられた【解消方法と原因考察】

2024/03/29に公開

前置き

入社3ヶ月目の駆け出しフロントエンドエンジニアによる備忘録です。
今回はNext.jsでTableタグを使用した際によく陥るエラーの解消方法と原因考察の記事となります。
解決策だけ知りたい人は さっそくやってみよう から読んで下さい。

◎ 今回やりたいこと

まず Next.js にて Tableタグを、

/src/components/ExampleTable.tsx
・・・ // importとかいろいろ

export default function ExampleTable() {
const exampleInfos = [・・・];  // tableタグに入力したいデータ
  return (
    <table>
      {exampleInfos.map((exampleInfo, index) => (  // trタグをデータの数だけ追加
        <tr key={index}>
          <th>{exampleInfo.tableHeading}</th>
          <td>{exampleInfo.tableData}</td>
        </tr>
      ))}
    </table>
  );
}

のように記述し、npm run dev したところ、
http://localhost:3000/ で下記のようなエラーが表示されました。

Next.jsでTableタグを使用した際に表示されたエラーの画像。1つ目。

Next.jsでTableタグを使用した際に表示されたエラー画像。2つ目。

最初はエラー文に従って解決方法を模索したのですが、残念ながら全く状況が改善されませんでした。

最終的に思わぬ形でエラーを解消できましたので、今回はその方法を共有していきたいと思います。同じ苦しみを味わう仲間が一人でも減ることを祈ります。

◎ さっそくやってみよう

エラー解消の方法は実に簡単です。
trを、thead または tbody tfoot のいずれかで囲めばよいだけです。
つまり、tableの直下に、丸裸の状態でtrを置くのを辞めるだけで今回のエラーをまとめて解消できます。

今回はtbodyタグで囲った例を以下に示します。
↓↓

/src/components/ExampleTable.tsx
  ・・・    // importとかいろいろ

 export default function ExampleTable() {
 const exampleInfos = [・・・];  // tableタグに入力したいデータ
  return (
    <table>
+      <tbody>
         {exampleInfos.map((exampleInfo, index) => (  // trタグをデータの数だけ追加
           <tr key={index}>
             <th>{exampleInfo.tableHeading}</th>
             <td>{exampleInfo.tableData}</td>
           </tr>
         ))}
+      </tbody>
    </table>
  );
}

これで無事エラーは解消されました。

◎ エラーの原因を考察する

まずはじめに「HTMLの入れ子のルールを破ってしまったのでは?」と疑ってみましたが、MDNで確認したところ、tableタグの直下にtrタグを入れ子にすることを禁止しているようには見受けられませんでした。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/table

ということは Next.js または React によるエラーであると考えられます。

どうやら ReactDOM.hydrateRoot はサーバサイドで生成された DOM 構造と、クライアントサイドで生成された 仮想DOM が一致していることを期待しており、仮想DOM では table > tr というデータ構造を想定していなかったため今回のようなエラーが発生してしまったようです。

つまり、MDNでは問題ないとされているHTML構造であっても、仮想DOMが想定しているHTML構造と一致しなかった場合は今回と同様のエラーが容赦なく飛んでくるという認識でいた方がよさそうですね。



うーんややこしい。
ちなみに私はこのエラーを自力での解決するのに軽く1時間半くらいは持っていかれました…
今回の記事が誰か1人でも悩める人を救うキッカケとなれば嬉しく思います。

Discussion