typescript - TanStack table | Hvordan kan jeg bruge en redux-handling i onPaginationChange i stedet for setPaginationState i eksemplet


Ved at bruge dette eksempel
https://tanstack.com/table/v8/docs/examples/react/pagination-controlled
Hvordan kan jeg bruge https://tanstack.com/table/v8/docs/api/features/pagination#onpaginationchange, hvis jeg har brug for at dispatch'e min redux-action i stedet for useState - setPaginationState?

onPaginationChange: state => dispatch(browseItemModalActions.setPagination(state))

får denne fejl i konsollen:

`react_devtools_backend.js:4012 A non-serializable value was detected in an action, in the path: `payload`. Value: old => {
          let newState = functionalUpdate(updater, old);
          return newState;
        } 

Svar #1

Dette er et interessant spørgsmål!

Baseret på den måde, eksemplet bruger onPaginationChange: setPagination, kunne man tro, at onPaginationChange-funktionen bliver kaldt med den nye tilstand, men det gør den ikke.

Din onPaginationChange-funktion bliver faktisk kaldt med en "opdaterings"-funktion, som tager den forrige tilstand og returnerer den nye tilstand. Dette virker med React setState-funktioner, fordi de understøtter funktionelle opdateringer, hvor du definerer din nye tilstand som en funktion af den forrige tilstand.

Med andre ord, når du ser dette:

onPaginationChange: setPagination,

Du tror, det gør dette:

onPaginationChange: (state) => setPagination(state),

Men det gør faktisk dette:

onPaginationChange: (updater) => setPagination(prevState => updater(prevState)),

Her er den relevante del af kildekoden til react-table:

setPagination: updater => {
  const safeUpdater: Updater<PaginationState> = old => {
    let newState = functionalUpdate(updater, old)

    return newState
  }

   return table.options.onPaginationChange?.(safeUpdater)
},

GitHub-kilde


Det er ikke indlysende eller nemt at bruge denne updater-funktion i en Redux-handling. Redux-reducere er "opdateringer" i sig selv, og handlingerne skal tage rådata.

I sidste ende kan du være nødt til at overveje, om det virkelig giver mening at gemme disse data i Redux. Jeg har nogle løsninger, men de har deres begrænsninger.

  1. Du kan beholde pagineringsstatus i komponenten og synkronisere ændringer tilbage til Redux med en useEffect-hook, men dette er en envejs-synkronisering og vil ikke fungere, hvis ændringer i Redux-pagineringsstatus kan komme fra andre handlinger.
const reduxPagination = useSelector((state) => state.counter.pagination);

const [pagination, setPagination] = React.useState(reduxPagination);

const { pageIndex, pageSize } = pagination;

const dispatch = useDispatch();

useEffect(() => {
  dispatch(browseItemModalActions.setPagination(pagination));
}, [pagination, dispatch]);
onPaginationChange: setPagination,
  1. Du kan anvende opdateringen til den tidligere valgte tilstand fra Redux og dispatch den opdaterede værdi.
const pagination = useSelector((state) => state.counter.pagination);

const dispatch = useDispatch();

const table = useReactTable({
  state: {
    pagination
  },
  onPaginationChange: (updater) => {
    const nextState = updater(pagination);
    dispatch(browseItemModalActions.setPagination(nextState));
  },
  manualPagination: true,
...

Men nu eksploderer mit hoved, fordi jeg får en TypeScript-fejl, der siger, at updater kan være enten en funktion eller en værdi... men vi har netop set på kildekoden, og det er altid en funktion! Så jeg ved ikke, hvad jeg skal gøre med dette længere. Det får mig til at spekulere på, om react-table-kildekoden er en fejl, og at callback'en er ment til at tillade almindelige dataværdier.

Svar #2

For dem, der bare vil hente den nye sideindeks og størrelse uden yderligere React.useState.

Da onPaginationChange-tilbagekaldelsen tager en updater som argument, kan du bare kalde den for at få den nye værdi.

onPaginationChange: (updater) => {
  // make sure updater is callable (to avoid typescript warning)
  if (typeof updater !== "function") return;

  const newPageInfo = updater(table.getState().pagination);

  console.log(table.getState().pagination);
  // output: {pageIndex: 0, pageSize: 30}

  console.log(newPageInfo);
  // output: {pageIndex: 1, pageSize: 30}
}

Du får også kodefuldførelse på VSCode efter at have skrevet newPageInfo.

Testet på react-table v8.

Relaterede artikler