Change Tracking
ChangeTracker monitors cell modifications and maintains a status lifecycle for each changed cell. This enables visual indicators (colored cell borders/backgrounds) that show users which cells have been modified, are being saved, or encountered errors.
Status Lifecycle
Section titled “Status Lifecycle”undefined → 'changed' → 'saving' → 'saved' ↘ 'error'- undefined — Cell has not been modified since baseline
- changed — Cell value differs from baseline
- saving — Save operation in progress
- saved — Successfully persisted (auto-clears after short delay)
- error — Save operation failed
View source code
import { useRef, useEffect, useState } from 'react';import { WitTable } from '@witqq/spreadsheet-react';import type { WitTableRef } from '@witqq/spreadsheet-react';import { DemoWrapper } from './DemoWrapper';import { generateEmployees, employeeColumns } from './generate-data';import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(30);
export function ChangeTrackingDemo() { const { witTheme } = useSiteTheme(); const tableRef = useRef<WitTableRef>(null); const [status, setStatus] = useState('Edit cells, then click "Simulate Save" to see the status lifecycle.');
useEffect(() => { const engine = tableRef.current?.getInstance(); if (!engine) return; engine.getChangeTracker().captureBaseline(); }, []);
const handleSimulateSave = async () => { const engine = tableRef.current?.getInstance(); if (!engine) return; const tracker = engine.getChangeTracker(); const changed = tracker.getChangedCells(); if (changed.length === 0) { setStatus('No changes to save. Edit some cells first.'); return; }
setStatus(`Saving ${changed.length} cell(s)...`); for (const cell of changed) { tracker.setCellStatus(cell.row, cell.col, 'saving'); } engine.requestRender();
await new Promise(r => setTimeout(r, 1000));
for (const cell of changed) { tracker.setCellStatus(cell.row, cell.col, 'saved'); } engine.requestRender(); setStatus(`Saved ${changed.length} cell(s). Status will clear shortly.`); };
return ( <DemoWrapper title="Live Demo" description="Edit cells to see 'changed' status (blue border). Click Save to see saving → saved lifecycle." height={440}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ padding: '0.5rem 0.75rem', borderBottom: '1px solid #e2e8f0', flexShrink: 0, display: 'flex', gap: '0.5rem', alignItems: 'center' }}> <button onClick={handleSimulateSave} style={{ padding: '4px 12px', cursor: 'pointer' }}>💾 Simulate Save</button> <span style={{ fontSize: '0.8rem', color: '#64748b' }}>{status}</span> </div> <div style={{ flex: 1 }}> <WitTable theme={witTheme} ref={tableRef} columns={employeeColumns} data={data} showRowNumbers editable style={{ width: '100%', height: '100%' }} /> </div> </div> </DemoWrapper> );}Table with Change Tracking
Section titled “Table with Change Tracking”import { useRef } from 'react';import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
function App() { const ref = useRef<WitTableRef>(null);
const handleSave = async () => { const tracker = ref.current?.getInstance().getChangeTracker(); const changed = tracker?.getChangedCells() ?? [];
for (const cell of changed) { tracker?.setCellStatus(cell.row, cell.col, 'saving'); }
try { await saveToBackend(changed); for (const cell of changed) { tracker?.setCellStatus(cell.row, cell.col, 'saved'); } } catch (err) { for (const cell of changed) { tracker?.setCellStatus(cell.row, cell.col, 'error'); } } };
return ( <> <button onClick={() => ref.current?.getInstance().getChangeTracker().captureBaseline()}> Capture Baseline </button> <button onClick={handleSave}>Save Changes</button> <WitTable ref={ref} columns={columns} data={data} editable={true} /> </> );}Async Save Flow
Section titled “Async Save Flow”Use setCellStatus to integrate with your backend save mechanism:
// Mark cells as savingtracker.setCellStatus(row, col, 'saving');
// On successtracker.setCellStatus(row, col, 'saved');
// On failuretracker.setCellStatus(row, col, 'error');API Reference
Section titled “API Reference”ChangeTracker
Section titled “ChangeTracker”| Method | Signature | Description |
|---|---|---|
captureBaseline | () => void | Snapshot current state as baseline |
setCellStatus | (row: number, col: number, status: CellStatus) => void | Set cell status |
getCellStatus | (row: number, col: number) => CellStatus | undefined | Get cell status |
getChangedCells | () => Array<{ row: number; col: number }> | List all modified cells |
clearChanges | () => void | Clear all tracking data |