0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(初心者向け)Tableコンポーネントの作成【React + TypeScript】

Last updated at Posted at 2025-11-18

目次

作成するテーブル

  • API実行時のレスポンスデータから取得した数値を表示したい
  • 1:00〜24:00までの1時間ごとの数値を表示したい
  • 1:00〜12:00、13:00〜24:00の2段に分けたい
  • 「使用量A」と「使用量B」の2つのテーブルを作成したい

完成イメージ

スクリーンショット 2025-11-18 11.03.29.png

APIのレスポンスデータは

{
    "id": 00046,
    "date": "2015-08-21",
    "area": 1,
    "amountUsedA01": 123,
    "amountUsedA02": 345.45,
    "amountUsedA03": 13.45,
     ・・・
    "amountUsedA24": 123.45,
    
    "amountUsedB01": 12.45,
    "amountUsedB02": 3.45,
    "amountUsedB03": 123.45,
     ・・・
    "amountUsedB24": 123.45
}

のように返却されるとします。

元の構造(マークアップ)

  <h2 className="c-heading02">使用量A</h2>
  <div className="c-table__wrap">
  <table className="c-table__contents">
    <tbody>
      <tr>
        <th>1:00</th>
        <th>2:00</th>
        <th>3:00</th>
        <th>4:00</th>
        <th>5:00</th>
        <th>6:00</th>
        <th>7:00</th>
        <th>8:00</th>
        <th>9:00</th>
        <th>10:00</th>
        <th>11:00</th>
        <th>12:00</th>
      </tr>
      <tr>
        <td>1.12</td>
        <td>14.2913</td>
        <td>7.36</td>  
        <td>10.44</td>
        <td>14.2913</td>
        <td>9.66</td>
        <td>4.66</td>
        <td>14.2913</td>
        <td>4.6</td>  
        <td>14.2913</td>
        <td>14.2913</td>
        <td>3.45</td>
      </tr>
      <tr>
        <th>13:00</th>
        <th>14:00</th>
        <th>15:00</th>
        <th>16:00</th>
        <th>17:00</th>
        <th>18:00</th>
        <th>19:00</th>
        <th>20:00</th>
        <th>21:00</th>
        <th>22:00</th>
        <th>23:00</th>
        <th>24:00</th>
      </tr>
      <tr>
        <td>1.12</td>
        <td>14.2913</td>
        <td>7.36</td>  
        <td>10.44</td>
        <td>14.2913</td>
        <td>9.66</td>
        <td>4.66</td>
        <td>14.2913</td>
        <td>4.6</td>  
        <td>14.2913</td>
        <td>14.2913</td>
        <td>3.45</td>
      </tr>
    </tbody>
  </table>
  </div>

  <h2 className="c-heading02">使用量B</h2>
  <div className="c-table__wrap">
  <table className="c-table__contents">
    <tbody>
      <tr>
        <th>1:00</th>
        <th>2:00</th>
        <th>3:00</th>
        <th>4:00</th>
        <th>5:00</th>
        <th>6:00</th>
        <th>7:00</th>
        <th>8:00</th>
        <th>9:00</th>
        <th>10:00</th>
        <th>11:00</th>
        <th>12:00</th>
      </tr>
      <tr>
        <td>0.0001</td>
        <td>0</td>
        <td>0.0001</td>  
        <td>14.2913</td>
        <td>0.0219</td>
        <td>0.0001</td>
        <td>0</td>
        <td>14.2913</td>
        <td>0.0001</td>  
        <td>14.2913</td>
        <td>0.0219</td>
        <td>0.0219</td>
      </tr>
      <tr>
        <th>13:00</th>
        <th>14:00</th>
        <th>15:00</th>
        <th>16:00</th>
        <th>17:00</th>
        <th>18:00</th>
        <th>19:00</th>
        <th>20:00</th>
        <th>21:00</th>
        <th>22:00</th>
        <th>23:00</th>
        <th>24:00</th>
      </tr>
      <tr>
        <td>0.0001</td>
        <td>0</td>
        <td>0.0001</td>  
        <td>14.2913</td>
        <td>0.0219</td>
        <td>0.0001</td>
        <td>0</td>
        <td>14.2913</td>
        <td>0.0001</td>  
        <td>14.2913</td>
        <td>0.0219</td>
        <td>0.0219</td>
      </tr>
    </tbody>
  </table>
  </div>

<tableタグ内の構造>
1段目のtr:1:00〜12:00の時間帯
2段目のtr:1:00〜12:00の数値
3段目のtr:13:00〜24:00の時間帯
4段目のtr:13:00〜24:00の数値
となっています。

このままでは重複している箇所が多く冗長です。
簡易なコードにしたいと思います。

修正後(React + TypeScript)

コンポーネント

仮のパス:src/features/amount-used/components/AmountUsedTable.tsx

import { AmountUsedApiResponse } from '@/core/api';

type Props = {
  data: AmountUsedApiResponse;
  itemName: string;
};

export const AmountUsedTable = ({ data, itemName }: Props) => {
  const generateHours = (from: number, to: number) =>
    Array.from({ length: to - from + 1 }, (_, i) => from + i);

  // 1段目のtr1:0012:00
  const firstHalfHours = generateHours(1, 12);
  
  // 3段目のtr1:0012:00
  const secondHalfHours = generateHours(13, 24);

  // 時間の行を作成
  const hourRow = (hours: number[]) => (
    <tr>
      {hours.map((h) => (
        <th key={h}>{h}:00</th>
      ))}
    </tr>
  );
  
  // 数値の行を作成
  const dataRow = (hours: number[]) => (
    <tr>
      {hours.map((h) => {
        const key = `${itemName}${String(h).padStart(2, '0')}` as keyof AmountUsedApiResponse;
        return <td key={h}>{data[key]}</td>;
      })}
    </tr>
  );

  return (
    <table className="c-table__contents">
      <tbody>
        {hourRow(firstHalfHours)}
        {dataRow(firstHalfHours)}
        {hourRow(secondHalfHours)}
        {dataRow(secondHalfHours)}
      </tbody>
    </table>
  );
};

コンポーネントを呼び出す

仮のパス:src/features/amount-used/AmountUsedPage.tsx
(画面表示の役割を持つファイル)

<h2 className="c-heading02">使用量A</h2>
<div className="c-table__wrap">
  <AmountUsedTable data={data} itemName="amountUsedA" />
</div>

<h2 className="c-heading02">使用量B</h2>
<div className="c-table__wrap">
  <AmountUsedTable data={data} itemName="amountUsedB" />
</div>

解説

Array.from()

  • 配列を生成するためのメソッド。
  • 反復可能オブジェクトや配列風オブジェクトからシャローコピーされた、新しいArrayインスタンスを生成する。(Array.from() | MDN より)
  • 第一引数:配列の長さを決める「配列風オブジェクト」
  • 第二引数:map関数(配列の各要素をどう生成するか)
const generateHours = (from: number, to: number) =>
    Array.from({ length: to - from + 1 }, (_, i) => from + i);

△「連続する時間の配列」を作成。

generateHours(1, 12)の場合、

const generateHours = (from: 1, to: 12) =>
    Array.from({ length: 12 - 1 + 1 }, (_, i) => 1 + i);

となる。

(_, i) => from + i
  • _ は配列の要素(今回は使わないので _ にしている)
  • i は インデックス番号(0から始まる)
  • from + iでは
    i=0 → from + 0 = 1
    i=1 → from + 1 = 2
    ...
    i=11 → from + 11 = 12
    となる。

配列の長さは12(12 個の要素を生成)となる。
fromからtoまでの連続する整数の配列を作成している。

Array.prototype.map()

  • Arrayインスタンスのメソッド。
  • 与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。(Array.prototype.map() | MDN より)
  const dataRow = (hours: number[]) => (
    <tr>
      {hours.map((h) => {
        const key = `${itemName}${String(h).padStart(2, '0')}` as keyof AmountUsedApiResponse;
        return <td key={h}>{data[key]}</td>;
      })}
    </tr>
  );
  • mapを使い、配列hoursの各時間(h)に対して処理する。
  • 各時間に対応するtdタグから成るセルを作成する。

String.prototype.padStart()

Table作成自体に関係はありませんが、紹介します。

  • ゼロ埋めを行う( 例:1月 → 01月 )
  • String 値のメソッド
  • 指定された文字列でこの文字列をパディングし(必要に応じて繰り返したり切り捨てたりして)、結果の文字列が指定された長さを示すようにする。
  • パディングは、この文字列の先頭から適用される。(String.prototype.padStart() | MDN より)
padStart(2, '0')
  • 第一引数:指定したい文字列の長さ。
  • 第二引数:第一引数で指定した長さになるまで繰り返す文字列。省略できる。
    ここではゼロ埋めしたいので「0」を指定し2桁の数値にしている。

keyの作成

const key =
 `${itemName}${String(h).padStart(2, '0')}` as keyof AmountUsedApiResponse;
  • itemName:ここでは「amountUsedA」か「amountUsedB」のいずれかが入る。
  • amountUsedA01, amountUsedA02, amountUsedA03・・・amountUsedA24ができる。

データを表示

<td key={h}>{data[key]}</td>
  • key={h}はReactのリストのキー(map内で必須)。
  • {data[key]}はdataオブジェクトの該当する値を表示する。
    例: data["amountUsedA01"] = 123

引用・参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?