【React】tr 中の th, td をループですっきり書く

  • 2021年5月25日
  • 2021年5月26日
  • React

 よく次の様なデータを

{
  "body": {
    "data": [
      {
        "memberId": 27,
        "name": "藤本 亮介",
        "funds": 62030,
        "companyName": "有限会社 宇野",
        "email": "kato.naoki@example.net",
        "createdAt": "2020-03-15 03:11:53"
      },
      {
        "memberId": 45,
        "name": "小泉ss 充cc",
        "funds": 12000,
        "companyName": "有限会社 宇野",
        "email": "hcccaruka.kimura@example.net",
        "createdAt": "2020-03-02 23:36:23"
      },
    ]
  }
}

 次のような HTML にして表示する時があります

<table>
  <thead>
    <tr>
      <th>名前</th>
      <th>資金</th>
      <th>会社</th>
      <th>メールアドレス</th>
      <th>登録日時</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>藤本 亮介</td>
      <td class="右寄せ">62,030</td>
      <td>有限会社 宇野</td>
      <td>kato.naoki@example.net</td>
      <td>2020-03-15 03:11:53</td>
    </tr>
    <tr>
      <td>小泉ss 充cc</td>
      <td class="右寄せ">12,000</td>
      <td>有限会社 宇野</td>
      <td>hcccaruka.kimura@example.net</td>
      <td>2020-03-02 23:36:23</td>
    </tr>
  </tbody>
</table>

 これを素直にテンプレートにすると次の様になります。

const MemberTable = () => {
  const data = {// 実際は axios か何かで外部からとってきて props で渡されることが多いです。
    body: {
      data: [
        {
          memberId: 27,
          name: '藤本 亮介',
          funds: 62030,
          companyName: '有限会社 宇野',
          email: 'kato.naoki@example.net',
          createdAt: '2020-03-15 03:11:53',
        },
        {
          memberId: 45,
          name: '小泉ss 充cc',
          funds: 12000,
          companyName: '有限会社 宇野',
          email: 'hcccaruka.kimura@example.net',
          createdAt: '2020-03-02 23:36:23',
        },
      ],
    },
  };

  return (
    <table>
      <thead>
        <tr>
          <th>名前</th>
          <th>資金</th>
          <th>会社</th>
          <th>メールアドレス</th>
          <th>登録日時</th>
        </tr>
      </thead>
      <tbody>
        {data.body.data.map((row) => {
          return (
            <tr>
              <td>{row.name}</td>
              <td class="右寄せ">{numberFormatInJS(row.funds)}</td>
              <td>{row.companyName}</td>
              <td>{row.email}</td>
              <td>{row.createdAt}</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
};

 このテンプレートは便利なのですが、表現すべき列が大量になってくるとテンプレートを書くのが恐ろしく手間になります。表中の列を並び替えたいという要望への対応などは列が少ない場合に比べて煩雑になります。
 これの対策としてでヘッダの名前とキーの名前をあらかじめまとめておく方法があります。これの実装が次です。

import React from 'react';

const TYPE_NUMBER = 'NUMBER';

const TABLE_DEFINE = [
  { label: '名前', key: 'name' },
  { label: '資金', key: 'funds', type: TYPE_NUMBER }, // 特別なパラメータや種別をあらかじめ定義
  { label: '会社', key: 'companyName' },
  { label: 'メールアドレス', key: 'email' },
  { label: '登録日時', key: 'createdAt' },
];

const MemberTable = () => {
  const data = '省略';

  return (
    <table>
      <thead>
        <tr>
          {/* 定義にしたがってヘッダを作成 */}
          {TABLE_DEFINE.map((def) => (
            <th key={def.key}>{def.label}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {/* 定義にしたがって各プロパティを呼び出して Cell を作成 */}
        {data.body.data.map((row) => (
          <tr key={row.memberId}>
            {TABLE_DEFINE.map((def) => {
              if (def.type === TYPE_NUMBER) {// もし数値ならば数値用のセルを用意
                return (
                  <td key={`${row.memberId} ${def.key}`} className="右寄せ">
                    {numberFormatInJS(row[def.key])}
                  </td>
                );
              }
              // 大半が使うデフォルトのセルをまとめて定義
              return <td key={`${row.memberId} ${def.key}`}>{row[def.key]}</td>;
            })}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

 大量の th, td を記述する必要がなくなるのが最大の利点です。また、上記例では TABLE_DEFINE を直に用いていますが一度変数に格納してその中で配列操作をすることによって、動的に見た目が変化する表を簡易に用意できます。要望としてデフォルトの列の並び順を変えたい時は TABLE_DEFINE 内の並び順で変えるだけで済みます。更にプロパティを増やして、結果読み取り用のキーの他に並び替え用カラム、背景色など色々定義するのも便利です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG