API Extensions
Extend the LyteNyte Grid API with additional properties for each grid instance. Use these properties to share custom functionality across renderers provided to the grid.
Grid API
The LyteNyte Grid API provides methods for programmatically handling common grid functionality,
such as selecting rows or toggling row groups. The grid passes an API reference to
every component callback, including cell and row detail renderers. You can also
obtain a reference to the API by providing a ref to the Grid component, as shown below:
function MyGrid() { const ref = useRef<Grid.API | null>(null);
return <Grid ref={ref} />;}Extending the API
Use the apiExtension property to add additional properties to the LyteNyte Grid API.
Extending the API lets you add bespoke functionality on top of the
existing API methods. For example, you can add a notify function as follows:
const extension = { notify: (msg: string) => { // Notify user },};
function MyGrid() { return <Grid apiExtension={extension} />;}The value of the apiExtension property must be an object. LyteNyte Grid assigns the
extension value onto a stable API reference. The API object reference in LyteNyte Grid never
changes, so it is not a reactive value. Changes to the value of apiExtension
apply to the API object, but these changes do not automatically trigger cell re-renders.
Function API Extension
The apiExtension property can accept a function that returns an object containing the additional API methods to add to the grid API.
The function form is called with a reference to a partial version of the grid API. You can safely capture this reference in your extension methods,
but do not call any API methods inside the extension function itself.
const myExtender = (api: Grid.API) => { // DO NOT USE THE API here api.props(); // This will throw
return { notify: (id: string) => { // Safe to use the API reference here. The function has captured the reference. api.columnById(id); }, };};The function form of the apiExtension is useful when the methods you add to the API need to call the grid API to perform work.
For example, you can add the ability to rename header cells by extending the API
with an updateHeaderName method. This method can then call api.columnUpdate to change the name of a column.
The demo below illustrates this approach. Try double-click the column header to rename it.
Supplying Reactive Values
Since the API reference never changes, any component that reads values from the API object will not
re-render when the apiExtension value changes. You may want to supply the API with a reactive value, such as
application state. The naive approach might look like this:
function MyGrid() { const [count, setCount] = useState(0);
const extension = useMemo(() => { return { count, setCount }; }, [count]);
return <Grid apiExtension={extension} />;}
// Then later in a component rendererconst IncrementRenderer = ({ api }) => { return ( <button onClick={() => { api.setCount((prev) => prev + 1); }} > Current Count: {count} </button> );};You may expect clicking IncrementRenderer to increment the displayed count, but it won’t.
When you click the button, the count does increment, but cells do not re-render because the API
object reference remains stable.
To make this work, you need to inject a hook for the state value. The exact approach varies depending on how you create state. If you use a state management library like Zustand or Jotai, you can add the store or atom to the API extension and then read the value from the store/atom in your component renderer. For example, with Jotai you can do the following:
import { atom, useAtom } from "jotai";
function MyGrid() { // This could be defined outside of MyGrid, but it's defined here // to demonstrate how state created in React components can be shared. const countAtom = useMemo(() => atom(0), []);
const extension = useMemo(() => { return { countAtom }; }, [countAtom]);
return <Grid apiExtension={extension} />;}
// Then later in a component rendererconst IncrementRenderer = ({ api }) => { const [count, setCount] = useAtom(api.countAtom);
return ( <button onClick={() => { setCount((prev) => prev + 1); }} > Current Count: {count} </button> );};Piece Utility
LyteNyte Grid provides the usePiece hook to simplify extending the API with reactive state.
This hook is convenient if you are not using an external state management library.
The usePiece hook creates a reactive watcher for the value you provide. You can then share the watcher
with other components, which can selectively update when the watched value changes. You can use
usePiece to extend the API as follows:
import { usePiece } from "@1771technologies/lytenyte-pro"; // core
function MyGrid() { const [count, setCount] = useState(0); const count$ = usePiece(count, setCount);
const extension = useMemo(() => { return { count$ }; }, [count$]);
return <Grid apiExtension={extension} />;}
// Then later in a component rendererconst IncrementRenderer = ({ api }) => { const count = api.count$.useValue(); return ( <button onClick={() => { api.count$.set((prev) => prev + 1); }} > Current Count: {count} </button> );};Note
The second parameter to usePiece is optional. If you provide it, the
returned piece becomes writable.
// A readonly piece valueconst count$ = usePiece(count);
// A read-write piece valueconst count$ = usePiece(count, setCount);Typing the API Extension
You can provide type information for API extensions using the GridSpec
interface. The example below shows the basic idea. See our
TypeScript guide for further information.
interface GridSpec { readonly api: { count$: PieceWritable<number>; };}
function MyGrid() { const [count, setCount] = useState(0); const count$ = usePiece(count, setCount);
const extension = useMemo(() => { return { count$ }; }, [count$]);
return <Grid<GridSpec> apiExtension={extension} />;}API & Row Source
LyteNyte Grid expects you to provide a value for the rowSource property. The grid uses this
property to define the row source implementation. The LyteNyte Grid API
also includes the properties of the RowSource you provide, so the grid API includes both
your apiExtension properties and the RowSource properties.
The code below results in an API that includes the ds value. The row source
provides useful functionality such as row retrieval and editing.
function MyGrid() { const ds = useClientRowSource({ ... });
return <Grid rowSource={ds} />;}Next Steps
- React Compiler: See how to use the React compiler with LyteNyte Grid to automatically memoize props.
- Grid Reactivity: Learn how LyteNyte Grid enables declarative reactivity.
- Columns Overview: Learn how column configuration influences the grid view.
