I have modified the Selection with Keys example to work with React. However as soon as I press an arrow key, the app crashes in the code below:
const [gridApi, setGridApi] = React.useState<GridApi | undefined>();
const onGridReady = (params: GridReadyEvent) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
console.log(gridApi); // log the latest gridApi instance if re-render
const keyboardNavigation = (
params: NavigateToNextCellParams
): CellPosition => {
// always reference the first instance of gridApi
if (gridApi === undefined) {
throw new Error("This should always happen!");
}
...
}
This is commonly known as stale closure in react hook. From my understanding here is what happen:
keyboardNavigation
is registered only once at the first render.keyboardNavigation
at that time references the gridApi
instance from the very first render which is undefined
.AgGridReact
in subsequent re-renders will use the first keyboardNavigation
instance, thus references the same old gridApi
even if it's been set now.You can verify that by logging the gridApi
in the render method, you can see from the second render, it has been initialized while your closure keyboardNavigation
still references the stale instance of gridApi
.
To fix that, you can change the code above to use reference instead of variable that can't be changed once baked in the closure.
type AgGridApi = {
grid?: GridApi;
column?: ColumnApi;
};
...
const apiRef = React.useRef<AgGridApi>({
grid: undefined,
column: undefined
});
const api = apiRef.current;
const onGridReady = (params: GridReadyEvent) => {
apiRef.current.grid = params.api;
apiRef.current.column = params.columnApi;
};
const yourCallback = () => {
api.grid?.doSomething()
api.column?.doSomething()
}