🍱
再帰処理で入れ子のテーブルコンポーネントを作る(折りたたみ機能付き!)
はじめに
再帰的なデータ構造に従って入れ子の(ネストされた)コンポーネントを実装してみました。
ミニマルな再帰コンポーネント
まずは、再帰処理の流れを掴むためにミニマルなコンポーネントの例を以下に示します。
実態としては、繰り返し {data.name}
を表示していくだけですね。
type Data = { name: string; children?: Data[] };
type Props = {
data: Data;
};
const RecursiveComponent = ({ data }: Props) => {
return (
<>
<div>{data.name}</div>
{data.children?.map((v) => {
return <RecursiveComponent key={v.name} data={v} />;
})}
</>
);
};
codesandobox も用意しました。手元で試せます!(注: サードパーティ cookie を無効にしていると見られません)
再帰的な入れ子テーブル
本記事のメインであるテーブルコンポーネントです。
折りたたみ機能も local state だけで済んでシンプルなところが気に入っています。
type User = {
name: string;
id: string;
favoriteColor: string;
children?: User[];
};
type UserRowProps = { user: User; level: number };
// 再帰処理しているコンポーネント
const UserRow = ({ user, level }: UserRowProps) => {
const [expanded, setExpanded] = useState(false);
// 階層を表現するために色と余白をつける
const rgb = 255 - 10 * level;
const color = `rgb(${rgb}, ${rgb}, ${rgb})`;
const space = `${level ? 8 + 4 * level : 8}px`;
return (
<>
<tr style={{ backgroundColor: color }}>
<td style={{ paddingLeft: space }}>{user.name}</td>
<td>{user.id}</td>
<td>{user.favoriteColor}</td>
<td>
{user.children?.length ? (
<button onClick={() => setExpanded((current) => !current)}>
{expanded ? "↑" : "↓"}
</button>
) : null}
</td>
</tr>
{expanded &&
user.children?.map((child) => {
return (
<UserRow
key={`${child.name}-${child.id}`}
user={child}
level={level + 1}
/>
);
})}
</>
);
};
type UserTableProps = {
users: User[];
};
const UserTable = ({ users }: UserTableProps) => {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>ID</th>
<th>Favorite Color</th>
<th />
</tr>
</thead>
<tbody>
{users.map((user) => (
<UserRow key={`${user.name}-${user.id}`} user={user} level={0} />
))}
</tbody>
</table>
);
};
<UserRow>
内で再帰処理を実行しています。
「入れ子」とは言っていますが、DOM 構造としては <tr>
がフラットに並んでいく感じになります。
<tbody>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</tbody>
こちらも codesandbox を用意しました。
おわりに
「再帰」と聞くと何だか複雑そうなイメージがありましたが。、多少克服できた気がします。やはり案ずるより産むが易しですね。
ぜひ「いいね!」をいただけると嬉しいです。
以上、お読みいただき、ありがとうございました。
Discussion