'How to structure this editable table in React
I'm trying to implement a table with the following features:
- The table will have hundreds of rows
- Each row can be selected/checked
- Each row has a 'note' (pops up a modal to edit the note)
- The table will have a 'select all' button to check all the rows
- Rows can be added/removed
My initial attempt was to structure the table like this (heavily pseudocoded to be concise):
let [rows, setRows] = useState("rows from an api");
let [showModal, setShowModal] = useState(false);
const checkAllRows = () => {
let stateRows = rows;
stateRows.map(row => row.checked = true);
setRows(stateRows);
}
const checkRow = (rowId) => {
let thisRow = rows.find(row => row.rowId === rowId);
thisRow.checked = true;
}
<button onClick={() => checkAllRows} />
<Table>
{rows.map(row => <Row row={row} checkRow={checkRow} setShowModal={setShowModal} />}
<NotesModal />
<Table>
Each row would:
const Row = (props) => {
let { row, checkRow, setShowModal } = props;
return (
<tr>
<td>some data</td>
<td><button onClick={() => checkRow(row.rowId)} /></td>
<td><button onClick={() => setShowModal(true)} /></td>
</tr>
);
}
However there are a two major issues that affect rendering.
First is the NotesModal. By keeping the NotesModal in the parent Table, I have only one modal that I can update with the selected row (save an activeRow in the parent tables state), however showing/hiding the modal causes the entire table to re-render because I'm setting the state of the parent table, which with hundreds of rows will be quite slow. I could move the NotesModal to each row which would then only render the individual row that's selected, but then I would have hundreds of Modals in the tree - seems like it would work fine but also seems like a bad practice.
Second, checking any individual row updates the rows in the parent state, which then causes the entire table to re-render. I tried using useMemo for each row and used the row properties as the dependents so individual rows would only re-render if they had to, but once a row was added/removed it blanked out. The more I looked into useMemo the more it seemed like I was trying to hack it into a place it wasn't meant to be used. I could potentially move the selected state of the row down into the Row component's state, however I don't know how I would implement the checkAllRows function because the checked state would now be down in the child component and the parent would not have direct access to it.
What's the best way to structure my state/functions to get this working without having things re-render all the time.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
