ag-Grid React melupakan gridApi setelah disetel

Sep 25 2020

Saya telah memodifikasi contoh Seleksi dengan Tombol untuk bekerja dengan React. Namun begitu saya menekan tombol panah, aplikasi macet dalam kode di bawah ini:

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

Saya menyetel gridApimenggunakan onGridReadysebelum tombol apa pun ditekan (dikonfirmasi dengan menambahkan a console.log). Jadi saya tidak tahu bagaimana hasilnya undefined.

Kode sumber lengkap saya ada di sini .

Jawaban

2 NearHuscarl Sep 26 2020 at 04:43
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!");
  }
  ...
}

Ini umumnya dikenal sebagai penutupan basi dalam kait reaksi. Dari pemahaman saya inilah yang terjadi:

  • Callback Anda keyboardNavigationhanya terdaftar sekali pada render pertama.
  • keyboardNavigationpada saat itu mereferensikan gridApiinstance dari render pertama yaitu undefined.
  • AgGridReactdalam perenderan ulang berikutnya akan menggunakan keyboardNavigationcontoh pertama , sehingga mereferensikan yang lama sama gridApi meskipun telah disetel sekarang.

Anda dapat memverifikasi bahwa dengan masuk ke gridApidalam metode render, Anda dapat melihat dari render kedua, ini telah diinisialisasi sementara closure Anda keyboardNavigationmasih mereferensikan instance basi dari gridApi.

Untuk memperbaikinya, Anda dapat mengubah kode di atas untuk menggunakan referensi, bukan variabel yang tidak dapat diubah setelah dimasukkan dalam 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()
}

Demo Langsung