0

here is my problem.

I am using react-window to render large tables. Each row has its own local state. After I delete a row, the next row moves up and gains the state of the deleted row (this how it looks in my app).

Is there a workaround for this problem? Can i have local state for each row with react-window?

codesandbox example | gif how it works

scrinpwnz
  • 15
  • 1
  • 3

2 Answers2

0

There is a fundamental issue here - react-window will dynamically render, unmount and rerender components. So if you want data persisted across re-renders - you must pass the count via props and a function to change it. Store the data with the item data itself.

I will try and show a working demo of that soon ,but look at this to understand yet another problem happening with this code: https://codesandbox.io/s/react-window-row-state-problem-mmukt

I have edited the size to be 150 instead of 50, this leads to the window getting a scrollbar. Now, try and click on "two" multiple times. This will increase the count. Next, scroll to bottom and go back up. You'll see that the count is lost.

This is because of the way react-window mounts and unmounts components.

To fix this in your original code, I made the following modifications: 1. Move count/active state to parent. 2. Pass the updateCount function to TableRow.

Essentially, the TableRow is now a pure component :)

Here is the link: https://codesandbox.io/s/react-window-row-state-problem-uzsdl

Hope this helps.

Sunny R Gupta
  • 5,026
  • 1
  • 31
  • 40
0

In a nutshell, you can't. The issue is that, when you delete an item, the same component that was used previously for it will be used to render the item after it (so if you delete the 2nd item, the 3rd item will use the Row from the old 2nd element). It will maintain that item's state. If you add a useEffect to detect that the item changed, then you break everything after it (since everything is bumped up one, all of the items after the deleted item will reset their state. You don't have access to the sibling component's state, so you have no way to propagate the state.

You have a few options here:

  1. Add the selection to the properties of the item, and provide a way to update the item.
  2. Make the selection state part of the App component's state, and pass it down to the component so it can render appropriately.

I'll also add that you probably don't want to map over your presumably large list of items every render like you are now. It looks like you are doing this to expose deleteItems. I would recommend something more like this:

<FixedSizeList
  height={500}
  width={300}
  itemCount={items.length}
  itemSize={50}
  itemData={{items, deleteItem}}
>
  {Row}
</FixedSizeList>

Then your Row component's data will have both the items array and the deleteItem function. If you maintain your selected rows state in App, you easily extend this to pass the selected state and modification functions down to your Row component.

rfestag
  • 1,913
  • 10
  • 20