ag-Grid React 在设置后忘记了 gridApi

ag-Grid React forgets gridApi after it has been set

我修改了 Selection with Keys 示例以使用 React。但是,一旦我按下箭头键,应用程序就会在以下代码中崩溃:

const [gridApi, setGridApi] = useState<GridApi | undefined>();

const handleGridReady = (event: GridReadyEvent) => {
  setGridApi(event.api);
  setGridColumnApi(event.columnApi);
};

const keyboardNavigation = (params: NavigateToNextCellParams): CellPosition => {
    if (gridApi === undefined) {
        throw new Error('This should never happen!');
    }
    ...
};

我在按下任何键之前使用 onGridReady 设置 gridApi(通过添加 console.log 确认)。所以我不知道它是如何变得 undefined.

我的完整源代码是 here

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!");
  }
  ...
}

这在 React Hook 中通常称为 stale closure。根据我的理解,这里发生了什么:

  • 您的回调 keyboardNavigation 仅在第一次渲染时注册一次。
  • 当时
  • keyboardNavigation 从第一个渲染中引用 gridApi 实例,即 undefined.
  • AgGridReact 在随后的 re-renders 中将使用第一个 keyboardNavigation 实例,因此引用 the same old gridApi 即使现在已设置。

您可以通过在渲染方法中记录 gridApi 来验证,您可以从第二个渲染中看到,它已经在您的 closure keyboardNavigation 仍然引用 gridApi.

stale 实例

要解决这个问题,您可以更改上面的代码以使用引用而不是变量,变量一旦在闭包中烘焙就无法更改。

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()
}

现场演示