constantin-p / cp-react-tree-table

A fast, efficient tree table component for ReactJS.
https://constantin.software/cp-react-tree-table
MIT License
94 stars 27 forks source link

Issue with scrolling #50

Closed aubsparrow closed 1 year ago

aubsparrow commented 1 year ago

I am having an issue where I have a checkbox on each row to select each row, but as I scroll through the other rows on the table the checkboxes that are checked change rows to the ones showing not the ones I actually selected.

constantin-p commented 1 year ago

Hi @aubsparrow, the TreeTable component renders a limited number of rows (enough to cover the viewport, plus a small top/bottom buffer) which are recycled when scrolling to keep initial rendering and interactions responsive even when using large data sets. It sounds like you're preserving the state of the checkbox outside the node's data, which would cause the effect you're describing where as the rows are recycled, the same checkbox states even are displayed even for new rows.

Storing the checked state within each node's data should address the issue. E.g.:

Pick a dedicated boolean field defined for each node to store the initial checked state:

[
    {
        data: { name: 'Node A', isChecked: true },
        children: [
            data: { name: 'Node A1', isChecked: false },
            data: { name: 'Node A2', isChecked: true }
        ]
    },
    { data: { name: 'Node B', isChecked: false } },
    { data: { name: 'Node C', isChecked: false } },
    // ...
]

... and inside the cell renderer corresponding to the column that will render the checkbox, use the Row APIs to access the state (row.data.isChecked), and also updated it (row.updateData({ ...row.data, isChecked: newValue })) when the checkbox is toggled:

<TreeTable
    value={treeValue}
    onChange={handleOnChange}>

    <TreeTable.Column
        renderHeaderCell={() => <span>Name</span>}
        renderCell={(row) => <span>{row.data.name}</span>}/>
    <TreeTable.Column
        renderHeaderCell={() => <span>Is Checked?</span>}
        //  ⌄ used to render all cells corresponding to the "Employees" column
        renderCell={(row) => 
            <input type="checkbox"
            //            ⌄ used to retrieve the checked state associated with the node represented by the current row
            checked={row.data.isChecked}
            onChange={(event) => {
                //  ⌄ used to store the new setting in the data of the node associated with the current row
                row.updateData({
                  ...row.data,
                  isChecked: event.target.checked,
                });
            }}/>}
        />
    ...
</TreeTable>

_Here is a working demo of the above pattern: JSFiddle link._ Screen Recording 2022-10-14 at 18 01 18