การนำ TabulatorPlus ไปใช้ใน React ให้มีประสิทธิภาพสูงสุด ( Production-ready ) จำเป็นต้องจัดการเรื่อง Lifecycle ของ Component ให้ดีครับ โดยเฉพาะการป้องกันไม่ให้เกิดการสร้าง Instance ซ้อนกันหลายตัว ( Double Initialization ) ซึ่งมักพบใน React 18+ ( Strict Mode )
นี่คือตัวอย่างโค้ดที่ครอบคลุมการจัดการ Instance, การ Refresh ข้อมูล และการ Unmount อย่างสะอาดครับ
ตัวอย่าง React Component: UserTable
import { useEffect, useRef } from 'react';
import TabulatorPlus from './TabulatorPlus';
// อย่าลืม import CSS ของ tabulator ในโปรเจกต์ด้วย
import "tabulator-tables/dist/css/tabulator.min.css";
function UserTable({ data }) {
const tableRef = useRef(null); // อ้างอิง DOM Element
const tabulatorInstance = useRef(null); // เก็บ Instance ไว้เพื่อเรียกใช้ Method อื่นๆ (Reused Instance)
// 1. Hook สำหรับการ Initialize และ Cleanup (Unmount)
useEffect(() => {
if (tableRef.current && !tabulatorInstance.current) {
// สร้าง Instance ครั้งแรก
tabulatorInstance.current = new TabulatorPlus(tableRef.current, {
data: data, // ข้อมูลเริ่มต้น
columns: [
{ title: "Name", field: "name", width: 150 },
{ title: "Age", field: "age", hozAlign: "left" },
{ title: "Status", field: "status", formatter: "tickCross" },
],
}, "user-table-storage");
}
// Cleanup: ล้างข้อมูลและทำลาย Instance เมื่อ Unmount
return () => {
if (tabulatorInstance.current) {
console.log("Cleaning up Tabulator instance...");
tabulatorInstance.current.destroy();
tabulatorInstance.current = null;
}
};
}, []); // ทำงานครั้งเดียวตอน Mount
// 2. Hook สำหรับการ Refresh ข้อมูล (เมื่อ Props 'data' เปลี่ยนแปลง)
useEffect(() => {
if (tabulatorInstance.current) {
console.log("Refreshing data...");
// ใช้ setData เพื่ออัปเดตข้อมูลโดยไม่สร้างตารางใหม่ (Performance ดีกว่า)
tabulatorInstance.current.setData(data);
}
}, [data]);
// 3. ฟังก์ชันสำหรับเรียกใช้งาน Instance จากภายนอก (Manual Refresh/Action)
const handleManualRefresh = () => {
if (tabulatorInstance.current) {
// เช่น สั่งให้ตารางวาดใหม่หลังเปลี่ยนขนาดหน้าจอ หรือล้าง Filter
tabulatorInstance.current.clearFilter(true);
tabulatorInstance.current.redraw(true);
}
};
return (
<div style={{ padding: "20px" }}>
<button
onClick={handleManualRefresh}
style={{ marginBottom: "10px" }}
>
Clear Filters & Redraw
</button>
{/* Element ที่ Tabulator จะไปเกาะ */}
<div ref={tableRef}></div>
</div>
);
}
export default UserTable;
คำอธิบายจุดสำคัญ
tabulatorInstance.current( Reused Instance ): เราใช้useRefเก็บตัวแปร Instance ไว้แทนuseStateเพราะเราไม่ต้องการให้ React ทำการ re-render ทุกครั้งที่ตัวแปรนี้เปลี่ยนค่า แต่เรายังต้องการอ้างอิงถึงมันเพื่อใช้ Method อย่าง.setData()หรือ.redraw()- การล้างข้อมูล ( Cleanup / Unmount ): ใน
returnของuseEffectชุดแรก เราสั่งtable.destroy()เพื่อให้ Tabulator ถอน Event Listeners และล้าง DOM ที่สร้างขึ้นทิ้ง ป้องกันปัญหา Memory Leak และอาการตารางซ้อนกัน - การ Refresh ( Data Syncing ): แทนที่จะสร้าง
new TabulatorPlusใหม่ทุกครั้งที่ข้อมูลเปลี่ยน ( ซึ่งจะทำให้ช้าและเสียสถานะการเรียงลำดับ ) เราใช้useEffectตัวที่สองมาดักจับการเปลี่ยนแปลงของdataแล้วใช้.setData()ซึ่งเป็นวิธีที่ Tabulator แนะนำครับ - Handling Strict Mode: การเช็ค
if (!tabulatorInstance.current)ช่วยป้องกันไม่ให้ React สร้างตาราง 2 รอบในโหมด Development ( Strict Mode )