JavaScript Tips | 配列ユーティリティ:UI 用整形

JavaScript JavaScript
スポンサーリンク

テーマの整理:「UI 用整形」とは何か

「UI 用整形」は、配列データを「画面コンポーネントが扱いやすい形」に変換するユーティリティのことです。 API や DB から取ってきた“生データ”は、そのままだと UI で使いづらいことが多いです。

例えばこういう悩みが出てきます。

  • テーブル表示用に「列ごとの値」「表示ラベル」「フォーマット済み文字列」が欲しい
  • セレクトボックス用に「value と label」のペアが欲しい
  • チェックボックスリスト用に「id・表示名・選択状態」が欲しい

UI 用整形ユーティリティは、 「画面側が欲しがる形」を決めて、そこに合わせて配列を変換する」ための道具です。

基本コンセプト:「生データ → UI コンポーネント用データ」に変換する

よくある“生データ”の例

例えば、こんなユーザー配列があるとします。

const users = [
  { id: 1, name: "Alice", role: "admin", active: true },
  { id: 2, name: "Bob",   role: "user",  active: false },
];
JavaScript

このままでも使えますが、UI では次のような形が欲しくなります。

  • テーブル用:列ごとに「表示ラベル」「フォーマット済み値」が欲しい
  • セレクトボックス用:{ value: id, label: name } の配列が欲しい
  • バッジ表示用:role を「管理者」「一般ユーザー」に変換したい

こういう「UI の都合」をコードにしたものが、UI 用整形ユーティリティです。

ユーティリティ 1:セレクトボックス用 { value, label } 配列に変換する

シナリオ

ユーザー一覧から、「ユーザー選択用のセレクトボックス」を作りたい。 欲しい形はこうです。

[
  { value: 1, label: "Alice" },
  { value: 2, label: "Bob"   },
]
JavaScript

実装:toOptions

function toOptions(records, valueField, labelField) {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }

  return records.map((r) => ({
    value: r[valueField],
    label: String(r[labelField]),
  }));
}
JavaScript

重要ポイントの深掘り

UI コンポーネントが期待する形を固定する 多くの UI ライブラリ(React Select など)は、 { value, label } という形を前提にしています。 ここでその形に揃えておくと、画面側のコードがシンプルになります。

label は必ず文字列にしておく String(r[labelField]) として、 数値や真偽値でも必ず文字列に変換しています。 UI は基本「文字列」を描画するので、ここで揃えておくと安心です。

例題 1:ユーザー配列をセレクトボックス用に整形する

const users = [
  { id: 1, name: "Alice", role: "admin", active: true },
  { id: 2, name: "Bob",   role: "user",  active: false },
];

const userOptions = toOptions(users, "id", "name");

console.log(userOptions);
JavaScript

出力イメージはこうなります。

[
  { value: 1, label: "Alice" },
  { value: 2, label: "Bob"   },
]
JavaScript

この形をそのまま <select> や UI ライブラリに渡せば、 「ユーザー選択 UI」がすぐ作れます。

ユーティリティ 2:テーブル表示用に「列定義+行データ」を整形する

シナリオ

ユーザー一覧をテーブルで表示したい。 UI コンポーネントが次のような形を期待しているとします。

const columns = [
  { key: "name",  header: "名前" },
  { key: "role",  header: "権限" },
  { key: "state", header: "状態" },
];

const rows = [
  { name: "Alice", role: "管理者", state: "有効" },
  { name: "Bob",   role: "一般",   state: "無効" },
];
JavaScript

表示用変換ルールを定義する

まず、「内部データ → 表示用文字列」の変換ルールを決めます。

const userDisplayMap = {
  role: (v) => (v === "admin" ? "管理者" : "一般"),
  active: (v) => (v ? "有効" : "無効"),
};
JavaScript

実装:toTableData

function toTableData(records) {
  if (!Array.isArray(records) || records.length === 0) {
    return { columns: [], rows: [] };
  }

  const columns = [
    { key: "name",  header: "名前" },
    { key: "role",  header: "権限" },
    { key: "state", header: "状態" },
  ];

  const rows = records.map((r) => ({
    name: r.name,
    role: userDisplayMap.role(r.role),
    state: userDisplayMap.active(r.active),
  }));

  return { columns, rows };
}
JavaScript

重要ポイントの深掘り

「内部の値」と「表示用の値」を分ける role は内部では "admin" | "user" ですが、 表示では「管理者」「一般」に変えています。 active は true/false を「有効」「無効」に変えています。

この「表示用変換」を UI 用整形の中でやっておくと、 画面側は「rows をそのまま描画するだけ」で済みます。

列定義を一箇所にまとめる columns をここで定義しておくことで、 「どの列を表示するか」「ヘッダ名は何か」が一目で分かります。 列追加・削除もこの関数だけ直せばよくなります。

例題 2:ユーザー配列をテーブル用に整形する

const users = [
  { id: 1, name: "Alice", role: "admin", active: true },
  { id: 2, name: "Bob",   role: "user",  active: false },
];

const table = toTableData(users);

console.log(JSON.stringify(table, null, 2));
JavaScript

出力イメージはこうなります。

{
  "columns": [
    { "key": "name",  "header": "名前" },
    { "key": "role",  "header": "権限" },
    { "key": "state", "header": "状態" }
  ],
  "rows": [
    { "name": "Alice", "role": "管理者", "state": "有効" },
    { "name": "Bob",   "role": "一般",   "state": "無効" }
  ]
}
JavaScript

この形をそのままテーブルコンポーネントに渡せば、 「日本語ラベル付きのきれいな一覧」が描画できます。

ユーティリティ 3:チェックボックスリスト用に「選択状態付き配列」を作る

シナリオ

ユーザー一覧から「権限付与対象ユーザー」を選ぶチェックボックスリストを作りたい。 欲しい形はこうです。

[
  { id: 1, label: "Alice", checked: false },
  { id: 2, label: "Bob",   checked: true  },
]
JavaScript

実装:toCheckboxItems

function toCheckboxItems(records, idField, labelField, selectedIds = []) {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }

  const selectedSet = new Set(selectedIds);

  return records.map((r) => ({
    id: r[idField],
    label: String(r[labelField]),
    checked: selectedSet.has(r[idField]),
  }));
}
JavaScript

重要ポイントの深掘り

選択状態を「配列 → Set」で高速に判定する selectedIds を Set に変換しておくことで、 selectedSet.has(...) で高速にチェックできます。 件数が増えてもパフォーマンスが落ちにくくなります。

UI 側は「checked をトグルするだけ」にする この形にしておくと、 画面側は「checked を true/false 切り替える」だけで状態管理ができます。 内部の id や name を意識する必要が減ります。

例題 3:ユーザー配列をチェックボックス用に整形する

const users = [
  { id: 1, name: "Alice", role: "admin", active: true },
  { id: 2, name: "Bob",   role: "user",  active: false },
];

const selectedIds = [2];

const items = toCheckboxItems(users, "id", "name", selectedIds);

console.log(items);
JavaScript

出力イメージはこうなります。

[
  { id: 1, label: "Alice", checked: false },
  { id: 2, label: "Bob",   checked: true  },
]
JavaScript

この形をそのままチェックボックスリストに渡せば、 「Bob にだけチェックが入った状態」で表示できます。

ユーティリティ 4:UI 用整形を「画面ごと」にまとめる

シナリオ

ユーザー画面、売上画面、商品画面など、 画面ごとに UI 用整形が増えていく。

整形関数をまとめたモジュールのイメージ

例えば、こんな感じでまとめておくと分かりやすいです。

export const UiShape = {
  users: {
    options: (users) => toOptions(users, "id", "name"),
    table:   (users) => toTableData(users),
    checkboxes: (users, selectedIds) =>
      toCheckboxItems(users, "id", "name", selectedIds),
  },
  // sales: { ... },
  // products: { ... },
};
JavaScript

使う側はこう書くだけになります。

const options   = UiShape.users.options(users);
const table     = UiShape.users.table(users);
const checkList = UiShape.users.checkboxes(users, [2]);
JavaScript

ここでのポイントは、

  • 「UI 用の形を作る処理」を一箇所に閉じ込めている
  • 画面側のコードは「どの整形を使うか」だけを意識すればよい

という状態を作っていることです。

UI 用整形ユーティリティで意識してほしい重要ポイント

「UI コンポーネントの都合」をちゃんとコードにする

UI 用整形の本質は、 「コンポーネントが欲しがる形」をちゃんと決めて、それに合わせて配列を変換する」ことです。

  • セレクトボックスなら { value, label }
  • テーブルなら { columns, rows }
  • チェックボックスなら { id, label, checked }

この“インターフェース”を決めておくと、 画面側のコードが驚くほどシンプルになります。

「生データを直接 UI に渡さない」癖をつける

生データには、

  • フィールド名が UI に向いていない
  • 値がそのままだと分かりづらい(コード値など)
  • 表示用のフォーマットが必要(日付・金額など)

といった問題が必ずあります。

UI 用整形ユーティリティを必ず通すことで、

  • フィールド名を UI 向けに揃える
  • コード値をラベルに変換する
  • 表示用フォーマットを適用する

という前処理を自動化できます。

手を動かして「UI 用整形」の感覚をつかむ

次のコードを実行して、

  • セレクトボックス用
  • テーブル用
  • チェックボックス用

の 3 パターンの整形を体感してみてください。

function toOptions(records, valueField, labelField) {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }
  return records.map((r) => ({
    value: r[valueField],
    label: String(r[labelField]),
  }));
}

const userDisplayMap = {
  role: (v) => (v === "admin" ? "管理者" : "一般"),
  active: (v) => (v ? "有効" : "無効"),
};

function toTableData(records) {
  if (!Array.isArray(records) || records.length === 0) {
    return { columns: [], rows: [] };
  }

  const columns = [
    { key: "name",  header: "名前" },
    { key: "role",  header: "権限" },
    { key: "state", header: "状態" },
  ];

  const rows = records.map((r) => ({
    name: r.name,
    role: userDisplayMap.role(r.role),
    state: userDisplayMap.active(r.active),
  }));

  return { columns, rows };
}

function toCheckboxItems(records, idField, labelField, selectedIds = []) {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }

  const selectedSet = new Set(selectedIds);

  return records.map((r) => ({
    id: r[idField],
    label: String(r[labelField]),
    checked: selectedSet.has(r[idField]),
  }));
}

function demo() {
  const users = [
    { id: 1, name: "Alice", role: "admin", active: true },
    { id: 2, name: "Bob",   role: "user",  active: false },
  ];

  console.log("=== options ===");
  console.log(toOptions(users, "id", "name"));

  console.log("=== table ===");
  console.log(JSON.stringify(toTableData(users), null, 2));

  console.log("=== checkboxes ===");
  console.log(toCheckboxItems(users, "id", "name", [2]));
}

demo();
JavaScript

まとめ:UI 用整形ユーティリティで「配列を、画面がそのまま使える形にする」

UI 用整形は、 「生の配列データを、UI コンポーネントがそのまま使える形に変えるためのユーティリティ」です。

プロジェクトでは、例えばこうまとめておくと扱いやすいです。

export const UiShape = {
  users: {
    options: (users) => toOptions(users, "id", "name"),
    table:   (users) => toTableData(users),
    checkboxes: (users, selectedIds) =>
      toCheckboxItems(users, "id", "name", selectedIds),
  },
};
JavaScript

そして、

  • 画面に渡す直前
  • コンポーネントに props を渡す直前

など、「UI に出す入口」で必ずこの整形を通す。

そうすると、 画面側は「どの整形を使うか」だけを考えればよくなり、 配列の中身や生データの都合に振り回されなくなります。

UI は“見せ方”、整形は“見せるための準備”。 その準備を自動化してくれるのが、UI 用整形ユーティリティです。

タイトルとURLをコピーしました