Tips & Tricks

Implementation: Claude Code 활용 가이드

implementation: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.

테이블컴포넌트の要件

데이터테이블は관리画面やダッシュボードの中心的なUIです。정렬、필터、페이지네이션、列のリサイズなど多くの機能が求められます。Claude Code를 활용하면 TanStack Tableをベースに高機能な테이블を빠르게구축할 수 있습니다。

TanStack Table에 의한基本구현

> TanStack Table를 사용한정렬・필터付き테이블を作って。
> 타입安全で、カラム定義を宣言的に書けるようにして。
import {
  useReactTable, getCoreRowModel, getSortedRowModel,
  getFilteredRowModel, getPaginationRowModel,
  flexRender, createColumnHelper, SortingState,
} from '@tanstack/react-table';
import { useState } from 'react';

interface User {
  id: string;
  name: string;
  email: string;
  role: string;
  createdAt: string;
}

const columnHelper = createColumnHelper<User>();

const columns = [
  columnHelper.accessor('name', {
    header: '名前',
    cell: (info) => <span className="font-medium">{info.getValue()}</span>,
  }),
  columnHelper.accessor('email', {
    header: 'メールアドレス',
  }),
  columnHelper.accessor('role', {
    header: '権限',
    cell: (info) => (
      <span className={`px-2 py-1 rounded text-xs ${
        info.getValue() === 'admin' ? 'bg-red-100 text-red-700' : 'bg-gray-100'
      }`}>
        {info.getValue()}
      </span>
    ),
  }),
  columnHelper.accessor('createdAt', {
    header: '登録日',
    cell: (info) => new Date(info.getValue()).toLocaleDateString('en-US'),
  }),
];

function DataTable({ data }: { data: User[] }) {
  const [sorting, setSorting] = useState<SortingState>([]);
  const [globalFilter, setGlobalFilter] = useState('');

  const table = useReactTable({
    data,
    columns,
    state: { sorting, globalFilter },
    onSortingChange: setSorting,
    onGlobalFilterChange: setGlobalFilter,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  });

  return (
    <div>
      <input
        value={globalFilter}
        onChange={(e) => setGlobalFilter(e.target.value)}
        placeholder="検索..."
        className="mb-4 px-3 py-2 border rounded w-full max-w-sm"
      />

      <table className="w-full border-collapse" role="grid">
        <thead>
          {table.getHeaderGroups().map((headerGroup) => (
            <tr key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <th
                  key={header.id}
                  onClick={header.column.getToggleSortingHandler()}
                  className="px-4 py-3 text-left bg-gray-50 border-b cursor-pointer select-none"
                  aria-sort={header.column.getIsSorted() === 'asc' ? 'ascending' : header.column.getIsSorted() === 'desc' ? 'descending' : 'none'}
                >
                  {flexRender(header.column.columnDef.header, header.getContext())}
                  {{ asc: ' ↑', desc: ' ↓' }[header.column.getIsSorted() as string] ?? ''}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody>
          {table.getRowModel().rows.map((row) => (
            <tr key={row.id} className="hover:bg-gray-50">
              {row.getVisibleCells().map((cell) => (
                <td key={cell.id} className="px-4 py-3 border-b">
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>

      <Pagination table={table} />
    </div>
  );
}

페이지네이션

function Pagination({ table }: { table: any }) {
  return (
    <div className="flex items-center justify-between mt-4">
      <span className="text-sm text-gray-500">
        全{table.getFilteredRowModel().rows.length}件中{' '}
        {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}〜
        {Math.min(
          (table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize,
          table.getFilteredRowModel().rows.length
        )}件
      </span>
      <div className="flex gap-2">
        <button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}
          className="px-3 py-1 border rounded disabled:opacity-50">Previous</button>
        <button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}
          className="px-3 py-1 border rounded disabled:opacity-50">Next</button>
      </div>
    </div>
  );
}

行선택と一括操作

const [rowSelection, setRowSelection] = useState({});

// 테이블설정に추가
const table = useReactTable({
  // ...既存の설정
  state: { sorting, globalFilter, rowSelection },
  onRowSelectionChange: setRowSelection,
  enableRowSelection: true,
});

// 一括操作버튼
const selectedCount = Object.keys(rowSelection).length;
{selectedCount > 0 && (
  <div className="mb-4 p-3 bg-blue-50 rounded flex items-center gap-4">
    <span>{selectedCount}件選択中</span>
    <button onClick={() => handleBulkDelete(table.getSelectedRowModel().rows)}>
      一括Delete
    </button>
  </div>
)}

정리

Claude Code를 활용하면 TanStack Tableベースの高機能테이블を정렬・필터・페이지네이션付きで빠르게구축할 수 있습니다。데이터の可視化は데이터可視化の글を、カレンダー표시はカレンダー컴포넌트를 참고하세요.

TanStack Table의 상세 정보는TanStack Table공식 문서를 확인하세요.

#Claude Code #table #React #TanStack Table #UI