😽

【NextJs14】NextJs14 と 便利なライブラリ【#17Shadcn-ui DataTable 】

2024/01/01に公開

【#17Shadcn-ui DataTable 】

YouTube: https://youtu.be/Qi2w3ZwCA-s

https://youtu.be/Qi2w3ZwCA-s

今回はDataTableを使用して、
フェッチしたデータを表示してみます。

https://ui.shadcn.com/docs/components/data-table

npx shadcn-ui@latest add table
npm install @tanstack/react-table
npm install axios

まずは新しくページを作成します。
フェッチするデータはこちらのusersを使用します。

https://jsonplaceholder.typicode.com/

app/(main)/data/page.tsx
import { User, columns } from "./_components/columns";
import { UsersDataTable } from "./_components/users-data-table";
import axios from "axios";

async function getData(): Promise<User[]> {
  try {
    const res = await axios.get("https://jsonplaceholder.typicode.com/users");
    return res.data;
  } catch (error) {
    console.log(error);
    return [];
  }
}

const DataPage = async () => {
  const data = await getData();

  return (
    <div className="container mx-auto py-10">
      <UsersDataTable columns={columns} data={data} />
    </div>
  );
};

export default DataPage;

そしてテーブル用のコンポーネントをdataフォルダに作成します。

app/(main)/data/_components/columns.tsx
"use client";

import { ColumnDef } from "@tanstack/react-table";

export type User = {
  id: number;
  name: string;
  username: string;
  email: string;
  address?: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    };
  };
  phone?: string;
  website?: string;
  company?: {
    name: string;
    catchPhrase: string;
    bs: string;
  };
};

export const columns: ColumnDef<User>[] = [
  {
    accessorKey: "id",
    header: "ID",
  },
  {
    accessorKey: "email",
    header: "Email",
  },
  {
    accessorKey: "username",
    header: "Username",
  },
  {
    accessorKey: "name",
    header: "Name",
  },
];
app/(main)/data/_components/users-data-table.tsx
"use client";

import {
  ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[];
  data: TData[];
}

export function UsersDataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return (
    <div className="rounded-md border">
      <Table>
        <TableHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map((header) => {
                return (
                  <TableHead key={header.id}>
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                  </TableHead>
                );
              })}
            </TableRow>
          ))}
        </TableHeader>
        <TableBody>
          {table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row) => (
              <TableRow
                key={row.id}
                data-state={row.getIsSelected() && "selected"}
              >
                {row.getVisibleCells().map((cell) => (
                  <TableCell key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </TableCell>
                ))}
              </TableRow>
            ))
          ) : (
            <TableRow>
              <TableCell colSpan={columns.length} className="h-24 text-center">
                No results.
              </TableCell>
            </TableRow>
          )}
        </TableBody>
      </Table>
    </div>
  );
}

Discussion