I want to implement a sortable table in React. I store the table's content as an array in a state variable using the useState
hook. Now, when I sort the array and update the content state variable, I would expect the table to re-render since I updated the state. Unfortunately, that is not the case and the table does not display the sorting.
Here is a simplified version of my issue. When I click on the table's header field "Name" I trigger the sorting and update of the state, but it does not rerender. Any idea what I am missing?
import { useState, useEffect } from 'react';
function App() {
type Entry = {
id: number;
name: string;
};
const [collection, setCollection] = useState<Entry[]>([]);
useEffect(()=> {
// just initially populating collection with data for testing purposes
setCollection([{id:1, name:"Ben"}, {id:2, name:"John"}, {id:3, name:"Anna"}])
}, [])
const byName = (a: Entry, b: Entry) => {
let x = a.name.toLowerCase();
let y = b.name.toLowerCase();
if (x < y) {return -1;}
if (x > y) {return 1;}
return 0;
}
return (
<div>
<table>
<tr id="head">
<th>Id</th>
<th onClick={() => setCollection(collection.sort(byName))}>Name</th>
</tr>
{collection.map((val, index) =>
<tr id={index.toString()}>
<td>{val.id}</td>
<td>{val.name}</td>
</tr>
)}
</table>
</div>
);
}
CodePudding user response:
The sort
function sorts in place and returns the same reference, so you are mutating state, not updating it.
Do
<th onClick={() => setCollection([...collection].sort(byName))}>Name</th>