ag-Grid React dimentica gridApi dopo che è stato impostato

Sep 25 2020

Ho modificato l' esempio Selection with Keys per lavorare con React. Tuttavia, non appena premo un tasto freccia, l'app si arresta in modo anomalo nel codice seguente:

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

Sto impostando l' gridApiuso onGridReadyprima di premere qualsiasi tasto (confermato aggiungendo a console.log). Quindi non so come stia andando undefined.

Il mio codice sorgente completo è qui .

Risposte

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

Questo è comunemente noto come chiusura stantia nel reagire hook. Dalla mia comprensione ecco cosa succede:

  • La tua richiamata keyboardNavigationviene registrata solo una volta al primo rendering.
  • keyboardNavigationin quel momento fa riferimento gridApiall'istanza dal primo rendering che è undefined.
  • AgGridReactnei successivi ri-rendering utilizzerà la prima keyboardNavigationistanza, quindi fa riferimento allo stesso vecchio gridApi anche se è stato impostato ora.

Puoi verificare che accedendo al gridApimetodo render, puoi vedere dal secondo rendering, che è stato inizializzato mentre la tua chiusura fa keyboardNavigation ancora riferimento all'istanza non aggiornata di gridApi.

Per risolvere questo problema, puoi modificare il codice sopra per utilizzare il riferimento invece della variabile che non può essere modificata una volta cotta nella chiusura.

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

Dimostrazione dal vivo