หมวดหมู่: React

React: TabulatorPlusReact: TabulatorPlus

การนำ 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 )