jbetancur / react-data-table-component

A responsive table library with built-in sorting, pagination, selection, expandable rows, and customizable styling.
https://react-data-table-component.netlify.app
Apache License 2.0
2.05k stars 413 forks source link

onSelectedRowsChange called by selectableRowSelected, infinite loop #930

Closed yuvachang closed 3 years ago

yuvachang commented 3 years ago

Describe the bug

Coming from v6.11.5 to v7+. No issue in v6.

My onSelectedRowsChange callback updates the data--part of what it does adds "isSelected: true" to the selected row. I then use selectableRowSelected = (row) => row.isSelected to keep that row selected when component updates with the new data.

However, right now, the onSelectedRowsChange callback is called on mount with selectedCount === 0 if a selectableRowSelected callback is provided to the DataTable component.

Infinite loop occurs if I select a row and onSelectedRowsChange updates data. The onSelectedRowsChange to get called with selectedCount === 0 and selectedCount === 1 over and over.

I hope this is makes sense. v6 the selectableRowSelected callback did not cause any extra onSelectedRowsChange calls, and I'm wondering if this is an intentional change. If it is, is there a 'correct' way of updating Table data while keeping rows selected?

I am passing the data from parent component as suggested: <Table cart rowData={lines} />

My DataTable in the Table component looks like this:

<DataTable
          columns={this.props.columns}
          dense
          data={this.props.rowData}
          noDataComponent={noDataComponent}
          pagination
          paginationPerPage={50}
          paginationRowsPerPageOptions={[10, 25, 50]}
          persistTableHead
          onSelectedRowsChange={this.handleSelectRow}
          selectableRows={selectableRows}
          selectableRowSelected={(row) => row.isSelected} // This causes the infinite loop, removing it stops the loop but won't render row as selected when the data updates.
          selectableRowDisabled={(row) => row.disableSelect}
          selectableRowsNoSelectAll={false}
          selectableRowsHighlight
          selectableRowsVisibleOnly={false}
          striped
/>

Expected behavior

onSelectedRowsChange callback ONLY called when user selects a row, not onMount of component/Table instance.

Versions (please complete the following information)

I know I'm probably not providing much, but please let me know what else I can share. Thanks!

jbetancur commented 3 years ago

This is definitely due to an internal change in V7 and I was able to duplicate an infinite loop if you try to to update state with the selectedRows provided in onSelectedRowsChange.

I'm going to look into why this is the case though but might take me some time to troubleshoot what changed. However, the intent of onSelectedRowsChange is not to update the data of the table, but rather for you to access RDT's internal state of selectedRows.

How are you updating isSelected? Are you making an API call out to do this? If so the result of that API updating state in its own effect call would then update data instead of via onSelectedRowsChange. RDT selectableRowSelected would then maintain the selected state without having to change the local data state.

What is your this.handleSelectRow code doing exactly?

yuvachang commented 3 years ago

Hey, thanks for speedy response, I appreciate the help!

My this.handleSelectRow is calling a Redux action (albeit no external API) that is also updating other components to respond to selected row(s) data. However, I am simultaneously reusing the Table component for different sets of data, so my this.handleSelectRow is updating the isSelected fields to track what's been selected in each set of data (users need to switch between data sets but keep previously selected rows). -- On v6, I believe this is behaving as intended because onSelectedRowsChange is triggered only once and selectableRowSelected is tracking row selection correctly with only one component update. ^ Is there a better/intended way of handling this (tracking selected rows on each data set) or am I practicing some anti-pattern?

Thanks again!! This is an amazing library and has been a lifesaving crux of my project.

jbetancur commented 3 years ago

Thank you! Hopefully I will have a fix for this soon.

jbetancur commented 3 years ago

Fixed in 7.4.2 - should be available shortly

jbetancur commented 3 years ago

7.4.2 is now available!

smartin36 commented 2 years ago

Thank you!

mayssalns commented 2 years ago

7.4.2 is now available!

The infinite loop still persists in versions v7.4.6, and v7.5, the function runs without the click action, causing an infinite loop.

v7.4.2 It works

PedroSass commented 2 years ago

7.4.2 is now available!

The infinite loop still persists in versions v7.4.6, and v7.5, the function runs without the click action, causing an infinite loop.

v7.4.2 It works

Thanks for the info, I didn't think downgrading would solve this problem. (Y)

AmityTek commented 2 years ago

On 7.4.7 the bug is still present ..

rajat-est commented 2 years ago

@jbetancur This issue is still present. Could you please review and update ?

rahulsrinivasan1 commented 2 years ago

@jbetancur Any update on the bug as even i am facing the same issue

GuYounes commented 2 years ago

@jbetancur Same issue here, any updates ?

gioserbug commented 2 years ago

@jbetancur any update about this bug? thanks!

aniket-solulab commented 2 years ago

@jbetancur any update on this bug issue still remains .

jbetancur commented 2 years ago

Sorry I've been away. I'll have a look this week.

rajat22999 commented 2 years ago

@jbetancur Yes, Please look into this. I'm still facing this issue. Hope you fix it soon.

musharafshaikh16 commented 9 months ago

Same here issue still exist!

M-Umais-Hassan commented 8 months ago

I think this is a kind of limitation or may be react-data-table-component team want us not to bind the table 2 way for selection purpose and the table will handle this on its own. Two way binding happens when we have a value prop e.g. selectableRowSelected and other thing we have is value change handler in our case it is "onSelectedRowsChange".

But the problem is, both of them are functions while ideally the value has not to be a function. I think this is the reason why infinite loop is causing.

So, I have solved it something like this, although it is not a good way but it will work,

const firstRender = useRef(true);

const selectProps = {
    ...(firstRender.current && {
      selectableRowSelected: () => preSelectRows(selected),
    }),
    ...(!firstRender.current && {
      onSelectedRowsChange: handleSelection,
    }),
  };

useEffect(() => firstRender.current = false, []);

<GenericDataTable
          {...selectProps}
          noDataComponent={<NoDataComponent />}
          persistTableHead={true}
          columns={columns}
          data={outletsListingData?.outlets}
          loading={loading}
          selectableRows={true}
          keyField="outlet_name_en"
/>

Any of your remarks are highly appreciated. Again that is not a valid solution, but it works for now.

BagusHartiansyah-2G18 commented 2 months ago

I saw the enthusiasm of my friends in finding a solution, finally I wanted to take part.

I have a method that starts from:

  1. create a variable count (state).
  2. method rowSelectCritera with action : _count((count+1)); return row.selected;
  3. Pay attention to the rendering update, I gave the value in the table rowSelectCritera={(count<dmember ? rowSelectCritera: false)}

hopefully can help

saya melihat semangat dari teman - teman dalam mencari solusinya, akhirnya saya ingin ikut andil. saya mempunyai cara yakni dimulai dari :

  1. membuat variable count (state).
  2. method rowSelectCritera dengan action : _count((count+1)); return row.selected;
  3. perhatikan update rendernya, saya memberi nilai pada tabel nya rowSelectCritera={(count<dmember ? rowSelectCritera: false)}

semoga dapat membantu