Row Model — ডেটার পাইপলাইন
core/filtered/sorted/grouped/expanded/paginated row model, pipeline ক্রম, getRowModel() কেন শেষে আসে, getRowId, debug করার উপায় — বাংলায়।
TanStack Table ডেটাকে একবারে রেন্ডার করে না। এটি একটা pipeline — প্রতিটি row model আগেরটার উপর কাজ করে, তাই সাজানোর ক্রম গুরুত্বপূর্ণ।
Pipeline টা দেখি
data (raw array)
│
├─ getCoreRowModel() → মূল row বানায় (raw → Row<T>)
│
├─ getFilteredRowModel() → filter মেরে বাকি রাখে
│
├─ getSortedRowModel() → সাজায়
│
├─ getGroupedRowModel() → group করে (grouped mode-এ)
│
├─ getExpandedRowModel() → sub-row খোলে/বন্ধ করে
│
└─ getPaginationRowModel()→ কয়টি row এই পেজে দেখাবে
table.getRowModel().rows ← রেন্ডারে এটাই ব্যবহার হয়getRowModel() সব model-কে খুলে দেয় — কিন্তু শুধু সেগুলোই যেগুলো আপনি useReactTable-এ দিয়েছেন। উপরের pipeline-এ getGroupedRowModel() না দিলে grouping-এর ধাপটাই থাকে না।
ছয়টি row model
| row model | কী করে | কোন state পড়ে | চালু করতে |
|---|---|---|---|
getCoreRowModel() | মূল row তৈরি | — | আবশ্যক |
getFilteredRowModel() | filter করে | globalFilter, columnFilters | filtering |
getSortedRowModel() | সাজায় | sorting | sorting |
getGroupedRowModel() | group করে | grouping | grouping |
getExpandedRowModel() | sub-row খোলে | expanded | nested data |
getPaginationRowModel() | পেজে ভাগ করে | pagination | pagination |
শুধু base (core) চাইলে অন্য পাঁচটাই বাদ — তাই ছোট টেবিলে অপ্রয়োজনীয় কোড বান্ডেলেও আসে না।
প্রতিটি model আলাদা করে দেখা
const table = useReactTable({
data: mockProducts,
columns,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
initialState: {
pagination: { pageSize: 5 },
sorting: [{ id: "price", desc: true }],
},
});
// console-এ মিলিয়ে দেখুন
console.log("raw:", mockProducts.length); // 12
console.log("core:", table.getCoreRowModel().rows.length); // 12
console.log("sorted:", table.getSortedRowModel().rows.length); // 12
console.log("final:", table.getRowModel().rows.length); // 5core আর sorted-এ row সংখ্যা সমান (সাজানো সংখ্যা বদলায় না), কিন্তু ক্রম বদলায়। আর final কম — কারণ pagination সবার শেষে। এই ক্রম না বুঝলে মনে হয় sorting কাজ করছে না।
ক্রম কেন এই রকম
ভাবুন ১০০০০ row, প্রতিটাতে search করতে হবে।
| ভুল ক্রম | ফল |
|---|---|
| sort → filter | ১০০০০ row সাজাও, তারপর ৩০টা বের করো |
| filter → sort | ৩০টা বের করে, তার ৩০টাই সাজাও |
ফিল্টার আগে, সাজানো পরে — এজন্যই pipeline-এর ক্রম এমন। এখানে মাত্র ৩ row বাঁচল, কিন্তু ১০০ row হলে প্রতিটা keystroke-এ তা লক্ষণীয়।
Expanded ও Grouped — কোথায় বসে
data
↓ core মূল row
↓ filtered filter
↓ sorted সাজানো
↓ grouped group header + aggregate
↓ expanded খোলা sub-row বের করে
↓ paginated পেজে ভাগgrouped ও expanded একটু বিশেষ: এরা filter/sort-এর আগে raw data-তে কাজ করে (grouped mode-এ sorting group-এর ক্রম ঠিক করে), আর পরে ফল খুলে দেখায়। তাই এই দুটো একসাথে ব্যবহার করলে মনে রাখবেন — grouping চালু থাকলে getSortedRowModel()-এর sorting header-এর ক্রমে কাজ করে, row-এর ক্রমে নয়।
getRowId — স্থায়ী row পরিচয়
এটা row model-এর অংশ না, কিন্তু এখানেই বসানো ভালো — কারণ এর ভুল প্রভাব পুরো pipeline-এ ছড়ায়।
// ছাড়া — row.id মানে index
getRowId: (row, index) => index, // "0", "1", "2" …
// সাধারণ ডেটাবেস ক্ষেত্রে
getRowId: (row) => row.id, // "p-01"
// ইনডেক্স-ভিত্তিক তবে স্থায়ী (সাজালেও বদলাবে না)
getRowId: (row, index) => row.id ?? `row-${index}`index-ভিত্তিক id সাজানোর পরই ভেঙে যায়। এর ফলে key={row.id} React-এর কাছে নতুন row ভাবে, selection চলে যায়, CSS transition ঝাঁপায়, আর <input>-এর focus হারায়।
Row model vs manual mode
row model = "table নিজে transform করবে"। এর বিপরীতে manual* মোড = "transform আমি server-এ করব, table শুধু state ধরে রাখুক"।
// client-side — table করবে
useReactTable({
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
// server-side — server করবে
useReactTable({
getCoreRowModel: getCoreRowModel(),
manualSorting: true,
manualPagination: true,
rowCount: 1284,
})manualSorting: true দিলে getSortedRowModel() আর কাজ করে না — manual flag তাকে উপেক্ষা করে। ফলে দুটোই দিলে বোঝা কঠিন বাগ পাবেন, কারণ state বদলায় কিন্তু কোনো দৃশ্যমান পরিবর্তন হয় না।
Filtered model-এর বিশেষত্ব
// filter-এর পরে কয়টা বাকি — এই তথ্য UI-তে দেখানোর কাজে লাগে
table.getFilteredRowModel().rows.length
table.getIsAllRowsFiltered()
table.getIsSomeRowsFiltered()
// নির্দিষ্ট কলাম বাদ দিলে কতটা বাকি
table.getColumn("price")?.getFilterValue()Server-side mode-এ getFilteredRowModel না দিলে getIsAllRowsFiltered() সবসময় false দেয় — কারণ table জানে না মোট কতটা ছিল। ফলে "কোনো ফলাফল নেই" বার্তা কখনও দেখাবে না।
Debug করার রুটিন
function debugTable(table: Table<Product>) {
const state = table.getState();
console.group("row models");
console.log("raw data :", table.getRowCount());
console.log("core :", table.getCoreRowModel().rows.length);
console.log("filtered :", table.getFilteredRowModel().rows.length);
console.log("sorted :", table.getSortedRowModel().rows.length);
console.log("final (view) :", table.getRowModel().rows.length);
console.groupEnd();
console.log("sorting :", state.sorting);
console.log("columnFilters:", state.columnFilters);
console.log("globalFilter :", JSON.stringify(state.globalFilter));
console.log("pagination :", state.pagination);
}বাগ হলে প্রথমে raw data সঠিক কিনা দেখুন, তারপর core, তারপর filtered। সাধারণত সমস্যা ডেটা বা filter-এ, row model-এ নয়।
| সমস্যা | কোথায় দেখবেন | সমাধান |
|---|---|---|
| কোনো row দেখাচ্ছে না | getCoreRowModel() | data খালি বা columns-এ accessor নেই |
| filter কাজ করে না | getFilteredRowModel() | getFilteredRowModel() দেওয়া হয়নি |
| sort দেখাচ্ছে না | getSortedRowModel() | sorting state ভুল id দিচ্ছে |
| পেজে ০টা row | getPaginationRowModel() | pageIndex অনেক বড় হয়ে গেছে |
| selection ভাঙে | row.id | getRowId বসান না |
| manual-এ কিছু হয় না | manual* | ঐ feature-এর row model দিয়ে দিয়েছেন |
সারসংক্ষেপ
getCoreRowModel()— একটাও বাদ দেওয়া যায় না- ক্রম: filtered → sorted → expanded → paginated
- রেন্ডার সবসময়
table.getRowModel()— বাকি model debug ও বিশেষ হিসাবে getRowIdছাড়া index-based id → selection ও focus ভাঙেmanual*চালু হলে ঐ feature-এর row model অপ্রয়োজনীয়
পরবর্তী
Pipeline বোঝা হয়ে গেছে। এবার প্রতিটি ধাপের feature আলাদা করে শিখি — পরের অধ্যায়ে sorting: state কীভাবে হয়, header-এ কীভাবে toggle হয়, আর custom comparator কোথায় লেখা হয়।