Chapter 07 of 34

GuiExpert Table in React

The same model, rendered by the React wrapper – with stable props via useMemo.

  • ⏱ 5 min
  • ▶ Video episode 007
  • git tag ep-007
  • needs @guiexpert/table@1.1.88

After this chapter you can

  • render <GuiexpertTable> in React
  • keep model and options stable
  • react to events with callback props

One core, thin wrappers

Every framework package is a thin layer over the core: it creates the TableScope of chapter 5 (First table), passes your model and options, and turns the table events into the idiom of the framework – callback props in React.

Eight thin wrappers on top of one framework-free core with zero runtime dependencies Your app Angular 14–22 React Vue 3 Svelte 4/5 Solid Preact Web Component Plain TS thin wrapper: creates the TableScope, maps events to props / outputs / CustomEvents @guiexpert/table – the core TableModel · TableOptions · TableScope · TableApi · renderers · CSS variables · 0 runtime dependencies → the same model and options work in every framework

Install

Terminal window
npm i @guiexpert/table @guiexpert/react-table
src/main.tsx
import "@guiexpert/table/css/main.css";

The component

The demo shows the shared orders model (the same as in chapter 6) and toggles between 100,000 and 1,000 rows:

frameworks/react/src/App.tsx
// Episode 007 – the same orders model, rendered by the React wrapper.
import { ComponentRendererWrapper, GuiexpertTable } from "@guiexpert/react-table";
import { GeMouseEvent, TableApi, TableOptions } from "@guiexpert/table";
import { useMemo, useState } from "react";
import { createOrderTableModel } from "./model/order-table";
import { StatusChip } from "./StatusChip";
export function App() {
const [rows, setRows] = useState(100_000);
const [info, setInfo] = useState("");
// a NEW model object rebuilds the table → keep model and options stable
const model = useMemo(() => createOrderTableModel(rows, {
status: new ComponentRendererWrapper(StatusChip) // episode 026: React component per cell
}), [rows]);
const options = useMemo(() => ({ ...new TableOptions() }), []);
const onReady = (api: TableApi) =>
setInfo(`${api.getBodyModel().getRowCount().toLocaleString("en")} orders`);
const onClick = (evt: GeMouseEvent) =>
setInfo(`row ${evt.rowIndex}, column ${evt.columnIndex}`);
return (
<>
<header className="app-header">
<b>React</b>
<button onClick={() => setRows(rows === 100_000 ? 1_000 : 100_000)}>
{rows === 100_000 ? "1,000 rows" : "100,000 rows"}
</button>
<span id="info">{info}</span>
</header>
<div className="table-div">
<GuiexpertTable
tableModel={model} tableOptions={options}
tableReady={onReady} mouseClicked={onClick}
/>
</div>
</>
);
}
React: the button builds a new model – and with it a new table.
React: the button builds a new model – and with it a new table.

Rules for React

  • A new tableModel or tableOptions object rebuilds the table (the wrapper uses useEffect([tableModel, tableOptions])). Create both with useMemo – otherwise every re-render of your component throws the table away, including scroll position and selection.
  • Callback props: tableReady, mouseClicked, selectionChanged, contextmenu, modelChanged, checkboxChanged, scroll … The callbacks may change on every render.
  • tableReady hands you the TableApi – keep it in a useRef if buttons need it.
  • The wrapper fills its parent (100 % × 100 %) – the parent needs a height.

React components inside cells

ComponentRendererWrapper turns a React component into a cell renderer – with working hooks. That is the topic of chapter 26 (Components as cells).

Next

The same model in chapter 8 (Vue 3).

API used in this chapter