This is an interesting question!
Based on the way that the example uses onPaginationChange: setPagination
you might think that the onPaginationChange
function gets called with the new state, but it does not.
Your onPaginationChange
function actually gets called with an "updater" function which takes the previous state and returns the new state. This works with React setState
functions because they support functional updates where you define your new state as a function of the previous state.
In other words, when you see this:
onPaginationChange: setPagination,
You think it's doing this:
onPaginationChange: (state) => setPagination(state),
But it's actually doing this:
onPaginationChange: (updater) => setPagination(prevState => updater(prevState)),
Here's the relevant part of the react-table source code:
setPagination: updater => {
const safeUpdater: Updater<PaginationState> = old => {
let newState = functionalUpdate(updater, old)
return newState
}
return table.options.onPaginationChange?.(safeUpdater)
},
GitHub Source
It is not obvious or easy to use this updater
function in a Redux action. Redux reducers are "updaters" of their own, and the actions must take raw data.
Ultimately, you may need to think about whether it really makes sense to store this data in Redux. I do have some workarounds but they have their limitations.
- You can keep the pagination state in the component and sync changes back to Redux with a
useEffect
hook, but this is a one-way syncing and won't work if changes to the Redux pagination state can come from other actions.
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,
- You can apply the updater to the previously-selected state from Redux and
dispatch
the updated value.
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,
...
But now my head is exploding because I'm getting a TypeScript error telling me that updater
could be either a function or a value...but we just looked at the source code and it's always a function! So I don't know what to make of this anymore. It makes me wonder if the react-table
source code is a mistake and the callback is meant to allow plain data values.