TanStack / table

🤖 Headless UI for building powerful tables & datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table
https://tanstack.com/table
MIT License
25.06k stars 3.07k forks source link

React: accessor function don't trigger when data is outside of exported component #4485

Open MortenEmde opened 1 year ago

MortenEmde commented 1 year ago

Describe the bug

We faced an issue regarding some cells in our application not triggering their translations correctly.

Looking at the attached codesandbox you can see 2 examples. One working and one not. We discovered that when data is defined outside the export of the component .accessor function don't trigger as expected.

Your minimal, reproducible example

https://codesandbox.io/s/i18next-react-table-forked-2znx8c?file=/src/NoWorks.tsx

Steps to reproduce

  1. Go to https://codesandbox.io/s/i18next-react-table-forked-2znx8c?file=/src/NoWorks.tsx
  2. Open console
  3. On default you see 'en' language logged by both the 'works' and 'noWorks' component.
  4. Click on Netherlands button
  5. You will see the 'works' rendered language console.log inside 'columnHelper.accessor' does correctly trigger
  6. You will also see the counter for 'noWorks' triggered but the rendered language console.log inside 'columnHelper.accessor' don't trigger
  7. Click on English button and see step 5 to 6 repeated.

Expected behavior

As a User I am expecting the accessor function to trigger despite the DataTable data being imported from outside the component or initiated inside the component.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

react-table version

v8.5.15

TypeScript version

v4.8.4

Additional context

No response

Terms & Code of Conduct

thomasmarr commented 1 year ago

It looks like tanstack table is memoizing the values returned by accessor functions internally, and they are only recalculated when the data is changed. If you wrap the data in the Works version in useMemo, it will stop working because data will be unchanged between renders.

I'm facing a similar but different issue where I would like a bit more control over when those values are invalidated. I wonder if @tannerlinsley or one of the other maintainers could provide a little explanation of what will trigger invalidation in the current setup? I would actually quite like to be able to manually trigger an update for a specific cell.

In my case, I have a datagrid where the data I pass into tanstack table contains a bunch of metadata fields relating to the row, (which make up the first 17 columns), and then there are a (potentially large) number of additional columns corresponding to calendar dates. In the cells for those columns I using some of the metadata from the row combined with the column date to lookup a value from a react-query cache. In other words I have stateful cells, and that state is managed in react-query. Those cells are user-editable, so when the query cache updates in response to a mutation, only the affected individual cell re-renders.

This approach keeps things extremely snappy from the user's point of view but it means I have to use queryClient.getQueryData to lookup the current cached value in the accessor (to enable e.g. sorting). Since I have poor visibility on when that value is being updated, I haven't figured out how to ensure that the values returned from the accessor function get refreshed when the react-query cache is updated in response to a cell mutation. If I was able to do this for the individual cell in the onSuccess callback of the mutation that would solve my particular needs. Something like cell.refreshValue(). But I guess it might also be nice to be able to do this for the whole table, or for a whole row or column.

MortenEmde commented 1 year ago

@KevinVandy @tannerlinsley do you have any update/information on this issue? Please see https://codesandbox.io/s/i18next-react-table-forked-2znx8c?file=/src/NoWorks.tsx as a example of the issue in question.

akibmayadav commented 1 year ago

Has there been an update on this issue? In my situation the user can change the formatting rules for cells in a table. The row accessor function in my column Definition function (using column helper) doesn't get updated.

llllvvuu commented 1 year ago

I had a similar issue here: https://github.com/TanStack/table/discussions/4739#discussioncomment-5995218

Currently I am doing a hacky thing of delete row._valuesCache[columnId]. But messing with library internals is icky so in the future I will just have my cells be React and my sorting functions be custom and not use getValues().

It would definitely be nice to have a noCache prop on the column, and/or table options. And then noCache could be checked here:

https://github.com/TanStack/table/blob/88977fa0aa9d714000069515f340e25a82c9217c/packages/table-core/src/core/row.ts#L43-L45

and here:

https://github.com/TanStack/table/blob/88977fa0aa9d714000069515f340e25a82c9217c/packages/table-core/src/core/row.ts#L61-L63

I actually can't imagine the cold path being that slow unless people are putting some crazy stuff in accessorFn. Probably such a noCache options would actually be quite popular?

coffenbacher commented 1 year ago

I am also running into this one. My table accepts a 'threshold' value that can be modified externally, and then the cell accessor makes a comparison with the threshold to say true/false.

I see that getValue is simply not called even when the rest of the tree is rendered, due to this issue. It's odd because the accessor function itself should be fairly light compared to the rest of the rendering Tanner recommends at https://github.com/TanStack/table/issues/4227. For that reason I think a noCache option would be great - only a tiny bit more code will execute (the accessors) in exchange for the whole tree re-render actually having an effect in this scenario.