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?

✅ 1. 型の宣言

SupplyInfo.tsx
type SortKey = "supplierCompany" | "supplier" | "purchasePlace" | "purchaseDate" | "lotNumber";
type SortDirection = "asc" | "desc";

・「型エイリアス(type alias)」の宣言です。つまり、「SortKey という名前の型は、特定の文字列しか取れませんよ」という制約を定義しています。

✅ 2. ソート状態の管理

SupplyInfo.tsx
const [sortConfig, setSortConfig] = useState<{
  key: SortKey | null;
  direction: SortDirection;
}>({ key: null, direction: "asc" });

・sortConfig は 現在のソートの設定情報(どの列を・どの順番で)を管理します。
・key はソート対象の列名(例: "supplierCompany" など)。初期値はnull。
・direction は "asc"(昇順)または "desc"(降順)。初期値はasc。

✅ 3. ソート処理(表示用データの並び替え)

SupplyInfo.tsx
const sortedProducts = [...filteredProducts].sort((a, b) => {
  const key = sortConfig.key;
  if (!key) return 0;

  let aVal: any = a[key];
  let bVal: any = b[key];

  // 日付は比較しやすいように数値化
  if (key === "purchaseDate") {
    aVal = aVal ? new Date(aVal).getTime() : 0;
    bVal = bVal ? new Date(bVal).getTime() : 0;
  }

  // null/undefined対策(空文字にする)
  aVal = aVal ?? "";
  bVal = bVal ?? "";

  if (typeof aVal === "number" && typeof bVal === "number") {
    return sortConfig.direction === "asc" ? aVal - bVal : bVal - aVal;
  }

  return sortConfig.direction === "asc"
    ? aVal.toString().localeCompare(bVal.toString())
    : bVal.toString().localeCompare(aVal.toString());
});

・filteredProducts(検索済みリスト)をコピー([...filteredProducts])して .sort() で並べ替え。
・key がなければ並び替えせずそのまま。
・特別な処理:
・purchaseDate は Date型 のため getTime() を使って数値に変換して比較。
・値が null や undefined の場合は "" に変換してエラーを防止。

・比較:
・数値なら単純に aVal - bVal などで比較。
・文字列なら localeCompare() を使い、文字順で並び替え。

✅ 4. ソートの切り替え処理(昇順・降順)

SupplyInfo.tsx
const handleSort = (key: SortKey) => {
  setSortConfig((prev) => ({
    key,
    direction: prev.key === key && prev.direction === "asc" ? "desc" : "asc",
  }));
};

・テーブルヘッダーをクリックしたときに呼び出されます。
・すでに選択されていた列を再度クリックしたら asc ⇄ desc の方向を反転。
・他の列をクリックしたら新しい列で "asc" から始める。

✅ 5. ソート可能なヘッダー(UIの表示と操作)

SupplyInfo.tsx
const renderSortHeader = (label: string, key: SortKey) => (
  <th
    onClick={() => handleSort(key)}
    className="p-2 border cursor-pointer hover:bg-gray-200"
  >
    {label}
    {sortConfig.key === key
      ? sortConfig.direction === "asc"
        ? ""
        : ""
      : ""}
  </th>
);

・label(見出し)と key(ソート対象)を受け取って

要素を返します。
・ヘッダーをクリックするとソート対象として選択され、昇順/降順が切り替わります。
・現在のソート対象に▲(昇順)または▼(降順)のマークを表示。
SupplyInfo.tsx
       {sortedProducts.map((item, index) => (
          <tr key={index} className="text-sm">
            <td className="p-2 border">{item.supplierCompany}</td>
            <td className="p-2 border">{item.supplier}</td>
            <td className="p-2 border">{item.purchasePlace}</td>
            <td className="p-2 border">
              {item.purchaseDate
                ? new Date(item.purchaseDate).toLocaleDateString()
                : "-"}
            </td>
            <td className="p-2 border">{item.lotNumber}</td>
          </tr>
部分 説明
sortedProducts.map(...) 商品データを1件ずつ取り出して表示する
(item, index) => (...) item は1件のデータ、index はそのインデックス
key={index} Reactに必要な一意のキー(※ユニークIDがあればそれを使うのが理想)

UI

画面収録 2025-07-18 8.00.43.gif

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?