✅ 1. 型の宣言
type SortKey = "supplierCompany" | "supplier" | "purchasePlace" | "purchaseDate" | "lotNumber";
type SortDirection = "asc" | "desc";
・「型エイリアス(type alias)」の宣言です。つまり、「SortKey という名前の型は、特定の文字列しか取れませんよ」という制約を定義しています。
✅ 2. ソート状態の管理
const [sortConfig, setSortConfig] = useState<{
key: SortKey | null;
direction: SortDirection;
}>({ key: null, direction: "asc" });
・sortConfig は 現在のソートの設定情報(どの列を・どの順番で)を管理します。
・key はソート対象の列名(例: "supplierCompany" など)。初期値はnull。
・direction は "asc"(昇順)または "desc"(降順)。初期値はasc。
✅ 3. ソート処理(表示用データの並び替え)
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. ソートの切り替え処理(昇順・降順)
const handleSort = (key: SortKey) => {
setSortConfig((prev) => ({
key,
direction: prev.key === key && prev.direction === "asc" ? "desc" : "asc",
}));
};
・テーブルヘッダーをクリックしたときに呼び出されます。
・すでに選択されていた列を再度クリックしたら asc ⇄ desc の方向を反転。
・他の列をクリックしたら新しい列で "asc" から始める。
✅ 5. ソート可能なヘッダー(UIの表示と操作)
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(ソート対象)を受け取って
要素を返します。・ヘッダーをクリックするとソート対象として選択され、昇順/降順が切り替わります。
・現在のソート対象に▲(昇順)または▼(降順)のマークを表示。
{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があればそれを使うのが理想) |