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?

React(Vue)で表を作成する

Last updated at Posted at 2025-09-17

はじめに

HTML,CSSで表の作成をしたことはあったが、Reactでの経験がないので備忘録として残します。
時間短縮のためにサンプルコードはclaude codeで出力しました。

サンプルコード

Table.tsx

import styles from "./table.module.css"

type TableData = {
  [key: string]: string | number;
};

type Props = {
  headers: string[];
  data: TableData[];
  className?: string;
};

/**
 * シンプルなテーブルコンポーネント
 *
 * @param param0 テーブルのヘッダーとデータ
 * @param param0.headers テーブルのヘッダー配列
 * @param param0.data テーブルのデータ配列
 * @param param0.className 追加のCSSクラス名
 * @returns JSX要素
 */
function Table({
  headers,
  data,
  className = ""
}: Props) {
  return (
    <div className={`${styles["table-container"]} ${className}`}>
      <table className={styles.table}>
        <thead>
          <tr>
            {headers.map((header, index) => (
              <th key={index} className={styles["table-header"]}>
                {header}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {data.map((row, rowIndex) => (
            <tr key={rowIndex} className={styles["table-row"]}>
              {headers.map((header, colIndex) => (
                <td key={colIndex} className={styles["table-cell"]}>
                  {row[header]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export default Table;

type TableData

type TableData = {
  [key: string]: string | number;
};

type TableData = ...TableDataという名前で型を定義
代入ではなく型の定義

{ [key: string]: string | number }
インデックスシグネチャと呼ばれる書き方。
値は string または number

配列ではなくオブジェクト!!

具体例

// ✅ OK: TableData はオブジェクト
const row: TableData = {
  name: "田中太郎",
  age: 30,
};

// ❌ NG: 配列ではない
const wrong: TableData = ["田中太郎", 30]; // エラー

type Props

type Props = {
  headers: string[];
  data: TableData[];
  className?: string;
};

Propsは 「このコンポーネントを使うときに渡せる引数の型
代入ではなく型の定義をしている

各プロパティの説明

headers: string[]

表のヘッダー(列名)を文字列の配列で渡す
例: ["名前", "年齢", "メール"]

data: TableData[]

→ 表の中身(行データの配列)。
1行分は TableData 型(オブジェクト)、それを複数集めた配列。

className?: string

→ 任意のCSSクラスを追加で渡せるようにする。
? がついているので「省略してもOK」。

function Table

function Table({
  headers,
  data,
  className = ""
}: Props) {

Tableという名前の関数を定義している
コンポーネントとして使えるようになる

引数部分の分解

{ headers, data, className = "" }
  • 通常なら props.headers のように書くけど
    • function Table(props: Props)
  • オブジェクトの分割代入 を使って直接 headersdata として受け取っている
    • デフォルト値を空文字にしているので、className を渡さなくてもエラーにならない
}: Props) {

引数全体がprops型だと表している

return

return (
    <div className={`${styles["table-container"]} ${className}`}>
      <table className={styles.table}>
        <thead>
          <tr>
            {headers.map((header, index) => (
              <th key={index} className={styles["table-header"]}>
                {header}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {data.map((row, rowIndex) => (
            <tr key={rowIndex} className={styles["table-row"]}>
              {headers.map((header, colIndex) => (
                <td key={colIndex} className={styles["table-cell"]}>
                  {row[header]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );

<div className={${styles["table-container"]} ${className}}>
→ CSSモジュールのクラス table-container と、外から渡された className を合体

<thead> 部分

<thead>
  <tr>
    {headers.map((header, index) => (
      <th key={index} className={styles["table-header"]}>
        {header}
      </th>
    ))}
  </tr>
</thead>

headers 配列を .map() でループして <th> を生成。

例: ["名前", "年齢"]

  • headers = ["名前", "年齢", "メール"] だとする

  • map が順番に処理していくとき

  1. header = "名前", index = 0
    <th key={0}>名前</th>

  2. header = "年齢", index = 1
    <th key={1}>年齢</th>

  3. header = "メール", index = 2
    <th key={2}>メール</th>

pythonのfor in みたいなイメージ?

<tbody>部分

<tbody>
  {data.map((row, rowIndex) => (
    <tr key={rowIndex} className={styles["table-row"]}>
      {headers.map((header, colIndex) => (
        <td key={colIndex} className={styles["table-cell"]}>
          {row[header]}
        </td>
      ))}
    </tr>
  ))}
</tbody>

data 配列(行データ)を .map() でループして <tr> を生成。

  • trは行を表している
{data.map((row, rowIndex) => (
    <tr key={rowIndex} className={styles["table-row"]}>
      {headers.map((header, colIndex) => (

ここで取得するのは1行分
例:{ "名前": "田中太郎", "年齢": 25, "職業": "エンジニア", "部署": "開発部" }

{headers.map((header, colIndex) => (
<td key={colIndex} className={styles["table-cell"]}>
  {row[header]}
</td>
  • headers.mapheadersを回している
  • {row[header]}で中身を取り出す

例:

  • 1回目ループ → header = "名前"
    • row[header] = row["名前"] = "田中"
  • 2回目ループ → header = "年齢"
    -row[header] = row["年齢"] = 30

TableTest.ts

import Table from '../../component/Table';

function TableTest() {
  const headers = ["名前", "年齢", "職業", "部署"];
  const data = [
    { "名前": "田中太郎", "年齢": 25, "職業": "エンジニア", "部署": "開発部" },
    { "名前": "佐藤花子", "年齢": 30, "職業": "デザイナー", "部署": "デザイン部" },
    { "名前": "鈴木次郎", "年齢": 28, "職業": "マネージャー", "部署": "企画部" },
    { "名前": "高橋美咲", "年齢": 32, "職業": "アナリスト", "部署": "分析部" }
  ];

  return (
    <div style={{ padding: "20px" }}>
      <h1>Tableコンポーネントテスト</h1>
      <Table headers={headers} data={data} />

      <h2 style={{ marginTop: "40px" }}>シンプルなテーブル</h2>
      <Table
        headers={["項目", ""]}
        data={[
          { "項目": "作成日", "": "2023-09-17" },
          { "項目": "更新日", "": "2023-09-17" },
          { "項目": "ステータス", "": "アクティブ" }
        ]}
      />
    </div>
  );
}

export default TableTest;

<Table headers={headers} data={data} />Tableコンポーネントにheadersとdataを渡している

追記

表を2つ渡せるようにした

function DoubleTables({
  table1,
  table2,
  className = ""
}: {
  table1: Props;
  table2: Props;
  className?: string;
}) {
  return (
    <div className={`${styles["double-tables"]} ${className}`}>
      <Table {...table1} />
      <Table {...table2} />
    </div>
  );
}

...スプレッド構文(spread syntax)と呼ばれるもの

スプレッド構文の基本

{...obj} と書くと、オブジェクトの中身を展開して渡すことができる

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?