برنامه نویسی

ساختن یک جدول قابل استفاده مجدد با React ، TypeScript ، tailwindcss و Shadcn/UI

بشر اما آنچه به عنوان یک کار آسان شروع می شود می تواند به سرعت در هنگام ساخت خود به یک کابوس تبدیل شود چندگانه جداول پراکنده در قسمتهای مختلف برنامه شما. ناگهان ، آنچه به نظر می رسید مانند یک حرکت بی ضرر در یک جانور مکنده زمان است.

حال تصور کنید که یک درخواست ویژگی در این زمینه قرار می گیرد: “سلام ، آیا می توانیم رنگ هدر جدول را تغییر دهیم؟ به اندازه کافی بی گناه به نظر می رسد ، درست است؟ اما پس از آن به شما برخورد می کند –شما باید به هر نمونه از هر جدول بروید برای به روزرسانی آنها به صورت دستی ، دعا می کنید که به طور تصادفی چیزی را در این روند بشکنید.

بله به شما گفت این می تواند یک درد در … خوب باشد ، بیایید فقط بگوییم “عقب مانده”.

اما نگران نباشید – من راه حلی دریافت کرده ام که جادویی تر از کلاه مرتب سازی هاگوارتز است! راز؟ اجزای قابل استفاده مجدد. با ترکیب مناسب ابزارها (فکر کنید واکنش ، TypeScript ، tailwindcss و یک تکه از Shadcn/UI) ، می توانید یک مؤلفه جدول را که همه کاره ، کارآمد و شادی برای حفظ آن است ، شلاق بزنید. برنامه نویسی تکراری نیست. در صورت تغییر نیازها ، هرج و مرج دیگری نیست.

آماده هستید تا ساعت ها کار و ناامیدی خود را نجات دهید؟ بیایید به معجون و طلسم ها شیرجه بزنیم –ر ، ابزارها – شما نیاز به ایجاد میزهایی دارید که مانند جادو کار کنند.

ابزارهایی که ما استفاده می کنیم

خوب ، بیایید در مورد سلاح های مخفی صحبت کنیم که این مؤلفه جدول را به عنوان یک ماشین خوب روغنی نرم و صاف می کند. ما فقط کتابخانه های تصادفی را به هم نمی ریزیم-ما از یک پشته با دقت استفاده می کنیم که همه چیز را سریع ، انعطاف پذیر و سازگار با توسعه دهنده نگه می دارد.

react.js (با vite)

معماری مبتنی بر مؤلفه React برای این کار مناسب است. به جای کپی کردن همان ساختار جدول در همه جا (که بیایید صادق باشیم ، مانند کابوس به نظر می رسد) ، ما یک مؤلفه جدول قابل استفاده مجدد ایجاد خواهیم کرد که با حداقل تلاش می تواند به هر قسمت از برنامه ما منتقل شود. و چرا ویت؟ چون است سریع-به طرز عجیبی ، تعجب خواهید کرد که چرا تا به حال با ابزارهای آهسته ساخته شده اید.

سیتن/پیاز

شما می توانست سبک های میز ، دکمه ها و کشویی را از ابتدا بسازید … یا فقط می توانید از Shadcn/UI استفاده کنید و خود را برای دردسر نجات دهید. این کتابخانه به ما اجزای ساخته شده و زیبا و زیبا را به ما می دهد که یکپارچه با Tailwindcss ادغام می شوند ، بنابراین می توانیم به جای گذراندن ساعت ها در سبک های تند و تیز ، روی ساخت جدول کار کنند.

پیچ و خم

صحبت از یک ظاهر طراحی شده ، tailwindcss به ما امکان می دهد سبک های تمیز و قابل حفظ را بنویسیم بدون غرق شدن در دریایی از پرونده های CSS سفارشی. نیاز به تنظیم فاصله دارید؟ اندازه قلم را تغییر دهید؟ رنگ ها را به روز کنید؟ فقط یک کلاس را در داخل مؤلفه قرار دهید. این مانند داشتن یک سیستم طراحی در نوک انگشتان شما است – بدون سردرد.

شرح

آیا تا به حال سعی کرده اید خطایی ناشی از انتقال داده های اشتباه به یک مؤلفه را اشکال زدایی کنید؟ اوقات سرگرم کننده TypeScript به ما کمک می کند تا با اجرای تعاریف سخت از نوع ، از این آشفتگی جلوگیری کنیم. این اطمینان حاصل می کند که ردیف ها ، ستون ها و اقدامات جدول ما به درستی ساختار یافته اند ، بنابراین ما به شگفتی های نامطبوع اجرا نمی شویم. به علاوه ، به ما می دهد خودکار برای ستون ها ، ردیف ها و انواع داده های جدول ما، ایجاد توسعه نرم تر و کاهش حدس. دیگر بین پرونده ها به عقب و عقب نمی روید تا به خاطر بسپارید که چه چیزی یک مؤلفه را انتظار دارد – Typescript پشت ما را دارد.

کد استودیو ویژوال (کد vs)

سرانجام ، هر جادوگر به یک گره احتیاج دارد ، و برای ما ، این است در مقابل کدبشر این سبک ، قدرتمند و پر از برنامه های افزودنی است که نوشتن و اشکال زدایی کد را به نسیم تبدیل می کند. با هوشمندانه، ما برای ساختار جدول خود به صورت خودکار در زمان واقعی دریافت می کنیم ، و اطمینان می دهیم که هرگز مجبور نیستیم نام ستون های حدس دوم یا خصوصیات ردیف را انجام دهیم.

نصب و راه اندازی

مرحله 1: یک پروژه React + Typescript را تنظیم کنید

دستور زیر را اجرا کنید

npm create vite@latest project-name
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

شرح تصویر

سپس انتخاب کنید Typescript:

شرح تصویر

پس از ایجاد پروژه ، به فهرست پروژه بروید و وابستگی ها را نصب کنید:

cd project-name
npm install
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اکنون ، پروژه را در VS Code باز کنید.

مرحله 2: نصب و پیکربندی Tailwind CSS (V4)

دستور زیر را برای نصب tailwindcss در پروژه خود اجرا کنید:

npm install tailwindcss @tailwindcss/vite
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بعد ، اضافه کنید @tailwindcss/vite افزونه به پیکربندی Vite شما. vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss()],
});
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

Tailwind CSS را به خود وارد کنید index.css

@import "tailwindcss";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مرحله 3: shadcn/ui را نصب کنید

ویرایش کردن tsconfig.json پرونده
نسخه فعلی Vite پیکربندی Typescript را در سه پرونده تقسیم می کند که دو مورد از آنها باید ویرایش شود. اضافه کردن baseUrl وت paths خواص به compilerOptions بخش tsconfig.json وت tsconfig.app.json پرونده ها

// tsconfig.json
"compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

ویرایش کردن tsconfig.app.json پرونده

کد زیر را به tsconfig.app.json پرونده برای حل مسیرها ، برای IDE خود:

// tsconfig.app.json
{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
    // ...
  }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

کد زیر را به vite.config.ts اضافه کنید تا برنامه شما بتواند مسیرها را بدون خطا برطرف کند

npm install -D @types/node
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

// vite.config.ts
**import { defineConfig } from "vite";
import path from "path";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اجرا shadcn-ui دستور اصلی برای تنظیم پروژه خود:

npx shadcn@latest init
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در حین تنظیم ، انتخاب کنید “تخته سنگ” به عنوان موضوع (یا هر موضوع دلخواه دیگر را انتخاب کنید).

شرح تصویر

برای تأیید نصب ، یک مؤلفه دکمه اضافه کنید:

npx shadcn@latest add button
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اگر همه چیز به درستی کار می کند ، اکنون باید یک مؤلفه دکمه به سبک Shadcn آماده استفاده از آن باشید!

مرحله 4: مؤلفه جدول را نصب کنید

از آنجا که ما در حال ساخت یک میز هستیم ، با اجرای برنامه ، مؤلفه جدول Shadcn را نصب کنید:

npx shadcn@latest add table
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بررسی نهایی

در این مرحله ، پروژه شما به طور کامل تنظیم شده است واکنش نشان دادنبا شرحبا tailwindcss 4وت سیتن/پیازبشر اگر به موضوعاتی رسیدید ، به راهنمای Vite Tailwindcss یا مستندات Shadcn/UI مراجعه کنید.

حال ، بیایید شروع به ساخت میز قابل استفاده مجدد خود کنیم! 🚀

ساخت جدول: جایی که جادو اتفاق می افتد

مرحله 1: رابط مؤلفه جدول را تعریف کنید

ایجاد a CustomDynamicTable.tsx مؤلفه زیر SRC/اجزای فهرست و انواع خود را تعریف کنید

type StringKeys<T> = Extract<keyof T, string>

export interface CustomDynamicTableProps<T> {
  tableData: T[]
  tableColumns: StringKeys<T>[]
  excludeColumns?: StringKeys<T>[]
  className?: string
  rowClassName?: string
  customHeadRender?: (col: StringKeys<T>) => ReactNode | null | undefined
  customBodyRender?: (rowData: T, col: StringKeys<T>) => ReactNode | null | undefined
  onRowClick?: (rowData: T) => void
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

چرا ما از Generic استفاده می کنیم (T)

ژنرال ها (T) مؤلفه جدول ما را بسازید سازگار به هر مجموعه داده ضمن اطمینان از ایمنی تایپبشر به جای قفل کردن جدول به یک نوع داده خاص ، T به عنوان یک مکان نگهدارنده انعطاف پذیر عمل می کند که بر اساس داده های ارائه شده تنظیم می شود.

نوع نام مستعار StringKeys فقط کلیدهای رشته را از نوع داده شده استخراج می کند T:

type StringKeys<T> = Extract<keyof T, string>;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این بدان معنی است که اگر داده های ما (ردیف داده های ما) (tableData) دارای خواصی مانند name یا age، فقط این کلیدها می توانند در آن گنجانده شوند tableColumnsبشر

🔒 دیگر خطایی وجود ندارد از مراجعه به یک کلید ستون که در داده ها وجود ندارد-فقط یک تجربه صاف و ایمن از نوع! 🚀


حتی با وجود این تنظیم ساده ، TypeScript در حال کار جادوی خود است. به این ساختار آرایه نگاهی بیندازید:

const employees: {
  id: number;
  name: string;
  age: number;
  department: string;
  position: string;
  salary: number;
  email: string;
  phone: string;
  address: string;
  isFullTime: boolean;
  skills: string[];
  manager: string;
}[];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مؤلفه جدول شما اکنون باید به این شکل باشد:

import { ReactNode } from "react";

type StringKeys<T> = Extract<keyof T, string>;

export interface CustomDynamicTableProps<T> {
  tableData: T[]; // Array of table row data
  tableColumns: StringKeys<T>[]; // Array of column keys to display
  excludeColumns?: StringKeys<T>[];
  className?: string;
  rowClassName?: string | ((row: T) => string);
  customHeadRender?: (col: StringKeys<T>) => ReactNode | null | undefined; // Custom render function for table headers
  customBodyRender?: (
    rowData: T,
    col: StringKeys<T>
  ) => ReactNode | null | undefined; // Custom render function for table cells
  onRowClick?: (rowData: T) => void; // Click handler for table rows
}

const CustomDynamicTable = <T extends object>(
  props: CustomDynamicTableProps<T>
) => {
  return <div>div>;
};

export default CustomDynamicTable;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بعد ، من وارد می کنم CustomDynamicTable.tsx به ما App.tsx جایی که می خواهم مؤلفه جدول خود را ارائه دهم. سپس من عبور کردم employees ساختار آرایه به tableDataبشر هنگام تعریف tableColumns prop ، typcript اطمینان می دهد که من فقط می توانم کلیدهای معتبر را از آن انتخاب کنم people ساختار آرایه.

همانطور که در تصویر زیر مشاهده می کنید ، ادغام TypeScript قطره ای از تمام کلیدهای معتبر را برای آن فراهم می کند tableColumns پروپ ، مانند "name"با "age"با "address"، و دیگران این محدودیت تضمین می کند که من نمی توانم به طور تصادفی به یک خاصیت نامعتبر یا غیر موجود مراجعه کنم ، و این مؤلفه را قوی تر ، و قابل اطمینان تر و به طور قابل توجهی اشکالات بالقوه کاهش می دهد.

شرح تصویر

ساخت میز UI:

بیایید ابتدا با وارد کردن مؤلفه جدول Shadcn که در آن نصب کردیم شروع کنیم CustomDynamicTable.tsx:

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بیایید جدول خود را با Generics Typescript آغاز کنیم

const CustomDynamicTable = <T extends object>(
  props: CustomDynamicTableProps<T>
) => {
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • تضمین می کند که این مؤلفه با هر داده ساختاری کار کند.
  • Typescript آن را اجرا می کند tableData مجموعه ای از اشیاء است که در آن tableColumns حاوی کلیدهای معتبر است.

اضافه کردن توابع یاور

function shouldRender(key: Extract<keyof T, string>) {
  if (excludeColumns.includes(key)) return false;
  return true;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در shouldRender عملکرد را بررسی می کند که آیا یک کلید ستون معین باید با اطمینان از ذکر نشده در آن نمایش داده شود excludeColumns آرایه این نوع ایمنی را فقط با پذیرش کلیدهای مبتنی بر رشته از نوع عمومی اعمال می کند T، جلوگیری از عبور کلیدهای نامعتبر. این کمک می کند تا به صورت پویا کنترل کنید که ستون ها در جدول ظاهر می شوند بدون اینکه به صورت دستی آنها را در جای دیگر فیلتر کند.

این را به خود اضافه کنید SRC/استفاده:

export function splitStringByUnderscore(str: string) {
  return str.split("_").join(" ");
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در splitStringByUnderscore عملکرد رشته های Snake_case را با جایگزین کردن زیرکرها با فضاها تبدیل می کند و آن را برای قالب بندی هدرها یا برچسب های ستون مفید می کند. من آن را در سود پوشه زیرا قابل استفاده مجدد است ، تابع خالص این به هیچ مؤلفه خاصی گره خورده نیست. این پایگاه کد را سازمان یافته تر و استفاده مجدد از طریق برنامه نگه می دارد.


ارائه هدرهای میز

 <TableHeader>
    <TableRow className="bg-muted">
      {tableColumns.map((col) => {
        return (
          <Fragment key={col}>
            {shouldRender(col) ? (
              <TableHead
                className={cn(
                  "whitespace-nowrap first-letter:capitalize"
                )}
              >
                {whatToRenderHeader(col)}
              TableHead>
            ) : null}
          Fragment>
        );
      })}
    TableRow>
  TableHeader>
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اضافه کردن whatToRenderHeader عمل

  const whatToRenderHeader = (col: StringKeys<T>) => {
    if (!shouldRender(col)) return null;
    const renderedContent = customHeadRender ? customHeadRender(col) : null;
    return renderedContent || splitStringByUnderscore(col);
  };
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در whatToRenderHeader تابع تعیین می کند که چگونه باید هر عنوان ستون با بررسی اینکه آیا باید ارائه شود ، نمایش داده شود و سپس استفاده از یک عملکرد رندر سفارشی ((customHeadRender) در صورت ارائه اگر عملکرد سفارشی در دسترس نیست ، به طور پیش فرض به splitStringByUnderscore قالب بندی کردن snake_case نام ستون به متن قابل خواندن. این عملکرد در درون منطق نقشه برداری هدر جدول استفاده می شود ، و اطمینان می دهد که فقط ستون های لازم با برچسب های به درستی قالب بندی شده نمایش داده می شوند

ارائه میز بدنه و سلول

  <TableBody>
    {tableData.map((row, idx) => {
      return (
        <TableRow
          key={idx}
          className={cn(
            typeof rowClassName === "function"
              ? rowClassName(row)
              : rowClassName
          )}
          onClick={() => handleRowClick(row)}
        >
          {tableColumns.map((col) => {
            return (
              <Fragment key={col}>
                {shouldRender(col) ? (
                  <TableCell className="whitespace-nowrap">
                    {whatToRenderBody(row, col)}
                  TableCell>
                ) : null}
              Fragment>
            );
          })}
        TableRow>
      );
    })}
  TableBody>
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اضافه کردن whatToRenderBody عمل

const whatToRenderBody = (row: T, col: StringKeys<T>) => {
  if (!shouldRender(col)) return null;
    const renderedContent = customBodyRender
      ? customBodyRender(row, col)
      : null;
    return renderedContent || (row[col] as ReactNode);
};
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

همچنین ، هنگامی که کاربر روی یک ردیف کلیک می کند ، عملکرد HandlerOwClick را اضافه کنید

// Memoized row click handler to prevent unnecessary re-renders
const handleRowClick = useCallback(
    (row: T) => {
      if (!onRowClick) return;
      onRowClick(row);
    },
    [onRowClick]
);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در tableData.map حلقه های عملکرد از طریق مجموعه داده ها ، ایجاد یک ردیف برای هر ورودی. داخل هر ردیف ، tableColumns.map برای تولید سلولهای جدول جداگانه از کلیدهای ستون تعریف شده عبور می کند. این باعث می شود جدول پویا باشد و به آن اجازه می دهد تا هر مجموعه ای از ستون های خاص را نشان دهد. در shouldRender(col) بررسی تضمین می کند که فقط ستون های لازم نمایش داده می شوند و همه چیز را تمیز و انعطاف پذیر نگه می دارند.

در rowClassName پروپ به شما کنترل می کند که چگونه هر سطر به نظر می رسد. اگر یک رشته را عبور دهید ، همان کلاس را در هر ردیف اعمال می کند و یک ظاهر طراحی شده را ثابت نگه می دارد. اما اگر یک تابع را منتقل کنید ، داده های ردیف را دریافت می کند و بر اساس محتوای آن کلاس را تصمیم می گیرد. این مفید است که شما نیاز به برجسته کردن ردیف های خاص داشته باشید-به عنوان مثال ، می توانید کارمندان را در بخش های خاصی با رنگ های مختلف برجسته کنید یا کارمندان پاره وقت را علامت گذاری کنید (isFullTime: false) با سابقه ای متفاوت برای متمایز کردن آنها از کارکنان تمام وقت. این انعطاف پذیری باعث می شود که از نظر بصری ردیف ها را بر اساس معیارهای معنی دار آسان کنید

در whatToRenderBody عملکرد دو استدلال می کند rol و col که تصمیم می گیرد چه چیزی باید در هر سلول جدول ظاهر شود. ابتدا بررسی می کند shouldRender(col) برای اطمینان از نمایش ستون. سپس ، اگر a customBodyRender عملکرد ارائه شده است ، به شما امکان می دهد نحوه نمایش محتوای سلول را مانند تاریخ قالب بندی یا تبدیل مقادیر تنظیم کنید. اگر نیازی به ارائه سفارشی نیست ، فقط داده های خام را از آن نمایش می دهد row[col]بشر این تنظیم باعث می شود جدول هم انعطاف پذیر و هم آسان باشد.

در handleRowClick عملکرد باعث تعاملی ردیف ها می شود. قبل از انجام هر کاری ، بررسی می کند که آیا onRowClick وجود دارد – اگر نه ، هیچ کاری انجام نمی دهد. اگر onRowClick عملکرد ارائه شده است ، آن را با داده های ردیف فعلی می نامد و به شما امکان می دهد اقداماتی مانند انتخاب یک ردیف یا حرکت به صفحه جزئیات را انجام دهید.

با استفاده از useCallback برای handleRowClick از بازگرداندن مجدد غیر ضروری جلوگیری می کند. به طور معمول ، توابع هر بار که یک مؤلفه مجدداً تولید می شوند ، دوباره ایجاد می شوند ، که در صورت انتقال به مؤلفه های کودک می توانند همه چیز را کاهش دهند. بسته بندی handleRowClick در useCallback تضمین می کند که فقط وقتی دوباره ایجاد می شود onRowClick تغییرات ، بهبود عملکرد ، به ویژه در جداول با داده های زیادی.

تصویر زیر نشان می دهد customBodyRender در عمل و ما برای هر یک از Typescript را به صورت خودکار دریافت می کنیم col با استفاده از مثال از rowClassName به عنوان function این یک نام کلاس را بر اساس شرایط اضافه می کند age ≤ 18

شرح تصویر

آنچه تاکنون ساخته شده است

import { Fragment, ReactNode, useCallback } from "react";
import { cn, splitStringByUnderscore } from "@/lib/utils";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

type StringKeys<T> = Extract<keyof T, string>;

export interface CustomDynamicTableProps<T> {
  tableData: T[]; // Array of table row data
  tableColumns: StringKeys<T>[]; // Array of column keys to display
  excludeColumns?: StringKeys<T>[];
  className?: string;
  rowClassName?: string | ((row: T) => string);
  customHeadRender?: (col: StringKeys<T>) => ReactNode | null | undefined; // Custom render function for table headers
  customBodyRender?: (
    rowData: T,
    col: StringKeys<T>
  ) => ReactNode | null | undefined; // Custom render function for table cells
  onRowClick?: (rowData: T) => void; // Click handler for table rows
}

const CustomDynamicTable = <T extends object>(
  props: CustomDynamicTableProps<T>
) => {
  const {
    tableColumns,
    tableData,
    excludeColumns = [],
    className,
    rowClassName = "",
    customHeadRender,
    customBodyRender,
    onRowClick,
  } = props;

  function shouldRender(key: StringKeys<T>) {
    if (excludeColumns.includes(key)) return false;
    return true;
  }

  const whatToRenderHeader = (col: StringKeys<T>) => {
    if (!shouldRender(col)) return null;
    const renderedContent = customHeadRender ? customHeadRender(col) : null;
    return renderedContent || splitStringByUnderscore(col);
  };

  const whatToRenderBody = (row: T, col: StringKeys<T>) => {
    if (!shouldRender(col)) return null;
    const renderedContent = customBodyRender
      ? customBodyRender(row, col)
      : null;
    return renderedContent || (row[col] as ReactNode);
  };

  // Memoized row click handler to prevent unnecessary re-renders
  const handleRowClick = useCallback(
    (row: T) => {
      if (!onRowClick) return;
      onRowClick(row);
    },
    [onRowClick]
  );

  return (
    <div className={cn("relative w-full overflow-auto", className)}>
      <Table>
        <TableHeader>
          <TableRow className="bg-muted">
            {tableColumns.map((col) => {
              return (
                <Fragment key={col}>
                  {shouldRender(col) ? (
                    <TableHead
                      className={cn(
                        "whitespace-nowrap first-letter:capitalize"
                      )}
                    >
                      {whatToRenderHeader(col)}
                    TableHead>
                  ) : null}
                Fragment>
              );
            })}
          TableRow>
        TableHeader>
        <TableBody>
          {tableData.map((row, idx) => {
            return (
              <TableRow
                key={idx}
                className={cn(
                  typeof rowClassName === "function"
                    ? rowClassName(row)
                    : rowClassName
                )}
                onClick={() => handleRowClick(row)}
              >
                {tableColumns.map((col) => {
                  return (
                    <Fragment key={col}>
                      {shouldRender(col) ? (
                        <TableCell className="whitespace-nowrap">
                          {whatToRenderBody(row, col)}
                        TableCell>
                      ) : null}
                    Fragment>
                  );
                })}
              TableRow>
            );
          })}
        TableBody>
      Table>
    div>
  );
};

export default CustomDynamicTable;

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

موارد آزمون:

1. به استثنای ستون های خاص

شما می توانید ستون های خاصی را از نمایش داده شده با استفاده از آن حذف کنید excludeColumns prop

<CustomDynamicTable
  tableData={employees}
  tableColumns={["name", "age", "email", "address", "phone"]}
  excludeColumns={["email", "phone"]} // These columns will be hidden
/>
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پنهان می کند "email" وت "phone" ستون ها هنگام نمایش بقیه

شرح تصویر

2. سفارشی سازی هدرهای جدول

 <CustomDynamicTable
    tableData={employees}
    tableColumns={["name", "age", "email"]}
    customHeadRender={(col) => {
      if (col === "email") {
        return (
          <span className="text-blue-500 font-bold uppercase">
            Email address
          span>
        );
      }
    }}
  />
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

عنوان ایمیل را هدف قرار داده و آن را از آن تغییر می دهد "Email" به "EMAIL ADDRESS" و یک رنگ متن آبی اضافه می کند.

شرح تصویر

3. سفارشی کردن سلولهای بدن میز

<CustomDynamicTable
  tableData={employees}
  tableColumns={["name", "age", "email"]}
  customBodyRender={(row, col) => {
    if (col === "age") {
      return <span className="text-green-600">{row.age} yearsspan>;
    }
    if (col === "email") {
      return <a href={`mailto:${row.email}`} className="text-blue-600 underline">
        {row.email}
      a>;
    }
  }}
/>
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اضافه کردن “سالها” به سن و یک ظاهر طراحی شده سفارشی و باعث می شود ایمیل ها قابل کلیک باشند.

شرح تصویر

4. کلیک روی ردیف

هنگامی که یک ردیف با استفاده از یک ردیف کلیک می شود ، تشخیص دهید onRowClickبشر

<CustomDynamicTable
  tableData={employees}
  tableColumns={["name", "age", "email"]}
  onRowClick={(row) => alert(`You clicked on ${row.name}`)}
/>
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با کلیک بر روی یک ردیف ، یک هشدار با نام کارمند ایجاد می کند.

شرح تصویر


بسته بندی آن

و درست مثل همین ، شما The Table Beast را کج کرده اید.

دیگر جداول پراکنده را در قسمت پایگاه کد خود شکار نکنید. به روزرسانی های دستی خسته کننده تر نیست. با داشتن یک مؤلفه جدول قابل استفاده مجدد ، شما سطح جدیدی از کارآیی را باز کرده اید-جایی که ترفندها بدون درد است ، سفارشی سازی یک نسیم است و خود آینده شما از شما برای پیش بینی تشکر می کند.

البته این فقط آغاز است. آیا می خواهید آن را حتی بیشتر کنید؟ ویرایش Inline ، پیمایش نامحدود یا تغییر اندازه ستون پویا را اضافه کنید. جادو در اینجا متوقف نمی شود. بنابراین به جلو بروید ، از قدرت های جدید روی میز خود استفاده کنید و UI خود را تمیز تر ، سریعتر و قابل حفظ تر کنید.

برنامه نویسی مبارک ، جادوگر! 🪄🚀

شما می توانید به من دسترسی پیدا کنید

وابسته به لینکدین

پیوند به مخزن:

https://github.com/paul-emas/reuseable-table

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا