I am using react-table v7 and I'm running into an issue where when I change one cell's data, the entire table re-renders. I have thousands of rows, so re-rendering every time is pretty slow.
My react-table calls a form that the user can fill out to delete an item from a particular row: the form calls an API that changes the data in the backend.
I want to be able to just re-render the cell containing the associated locations for the article that I am editing, in order to reflect that I've deleted a location from that cell.
Articles Associated Locations
Article 1 **Paris, Brazil**
Article 2 Idaho, Illinois
would become:
Articles Associated Locations
Article 1 **Paris**
Article 2 Idaho, Illinois
such that I would only re-render the top right cell.
Simplified code:
App.js:
function App() {
const columns = useMemo(
() => [
{
columns: [
{
Header: "Article",
accessor: "headline",
Cell: row => (
<div>
{row.original.headline}
</div>
)
},
{
Header: "Locations",
id: "locations",
Cell: ({ row }) => (
<div>
{row.original.tags}
</div>
)
},
]
}
],
[]
);
const [data, setData] = useState([]);
useEffect(() => {
(async () => {
const result = await axios("/articles"); // fetch data from an API
setData(result.data);
})();
}, []);
return (
<div className="App">
<Table columns={columns} data={data} />
</div>
);
}
export default App;
App.js calls Table.js:
Table.js:
export default function Table({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
} = useTable(
{
columns,
data,
},
);
const renderRowSubComponent = React.useCallback(({ row }) => {
return (
<>
<DeleteForm id={row.original.article_id} row={row} ></DeleteForm>
</>
);
}
);
// Render the UI for your table
return (
<>
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
className={
column.isSorted
? column.isSortedDesc
? "sort-desc"
: "sort-asc"
: ""
}
>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
etc.
And Table.js has a DeleteForm, which I use to call an API that deletes a selected location from an article:
DeleteForm.js:
class DeleteForm extends Component {
constructor(props){
super(props);
this.state = {
article_id: 0,
inputLoc: null,
locations: [],
};
}
onChange = e => {
this.setState({inputLoc: e.target.value}, () => {
console.log(this.state.inputLoc, 'inputLoc')
})};
deleteLocAssociation = () => {
fetch...
// API call that deletes the location in the backend
this.setState({locations: APIResults})
}
componentDidMount(){
if(this.state.inputLoc){
this.deleteLocAssociation();
}
}
render() {
const row = this.props.row
return (
<Form onSubmit={this.deleteLocAssociation}>
// Form for user to input a location
</Form>
)
}
}
export default DeleteForm
I've been scoping out Stack Overflow and the closest questions I could find were:
- react-table re-renders entire table on select: Not helpful since I don't want to have to downgrade my react-table to v6
- select row on click react-table: Found this about selecting a specific row in react-table, but not sure how I could apply that to re-rendering a selected row
- react-table keeps re-rendering unchanged cells: unanswered
Some places say that virtualization or pagination might help, but I do want to render everything in my table at first, since I have a search function to look up data and I want all data to be available.