DevExpress / devextreme-reactive

Business React components for Bootstrap and Material-UI
https://devexpress.github.io/devextreme-reactive/
Other
2.08k stars 380 forks source link

Editable Redux backed Virtual Table #2704

Open PilchardFriendly opened 4 years ago

PilchardFriendly commented 4 years ago

I'm using ...

Description

We have started to Add editable components to our Virtual Table, and have run in to some complexities around cache invalidation.

We are using Redux for state management, and have reducers that present the most recent page loaded and the skip value. As the user scrolls we notice that

Set up

Given: a). The redux state does contains the most recent loaded data (e.g. based on time(n)) b). The Virtual table 'rows' prop mirrors the redux state c). The virtual table also displays older data around that page (e.g. based on time(n-1), time(n-2). The components and model for these rows are held in a cache. d). The cache elements are now disconnected from the redux state When: a) We edit a value in a cell component in page from (time(n-1) or time(n-2) b) Save that change via a Redux command Then a) The the remote update will occur, and dispatch into Redux b) The the update to the cached entry is no longer in Redux state, so the update will be a noop. c) The user does not see their change reflected in the visible component.

The desired behaviour is that update consistency from Redux is maintained for cached rows.

Things we've tried:

1) Returning all possible rows loaded to the 'rows' prop. => A repeating eternally growing paged list, and update inconsistencies. 2) Using the Editable Table plug in, hoping that it would force a round trip for cached entries => It does not force a cache invalidation 3) Create a custom cache and inject it into VirtualTableState => There are no obvious hooks to do this

Things we're going to try:

1) Overriding the VirtualTableState and hooking into to how the VirtualRows are managed 2) Binding an Action that can be invoked to rebind cached entries when Editing is required

Things we could use if they were available:

Any of: a) Control over cache entry invalidation b) Hooks to allow editing to revalidate the cache c) A way to bind a Redux model that interacts with the caching strategy. d) some other way of solving the "cache invalidation

ushkal commented 4 years ago

Hi @PilchardFriendly ,

I recommend you try the following approach: use redux-thunk middleware and update the current page in the cache when committing row changes. The code snippet below illustrates this idea.

const updateRow = (changed) => (dispatch, getState) => {
  const changedIndex = Object.keys(changed)[0];
  const skip = Math.round(changedIndex / VIRTUAL_PAGE_SIZE) * VIRTUAL_PAGE_SIZE;
  const currentPage = cache.getRows(skip, VIRTUAL_PAGE_SIZE);
  const updatedPage = currentPage.map(row => (changed[row.id] ? { ...row, ...changed[row.id] } : row));

  dispatch(saveRows(changed));
  dispatch(updateCache(skip, updatedPage));
}

const updateCache = (skip, rows) => (dispatch) => {
  cache.setRows(skip, rows);
  dispatch(updateRows(skip, cache.getRows(skip, VIRTUAL_PAGE_SIZE)));
}

const updateRows = (skip, rows) => ({
  type: 'UPDATE_ROWS',
  rows,
  skip,
});

const saveRows = changed => {
  // perform api call
};

Please let me know if it helps.

I also appreciate you sharing your suggestions regarding the caching mechanism. We'll consider them when discussing new features.