I have a list of students and I display them on the table. There are two buttons that indicate by which value should I sort the list (name or birthdate). When the button is clicked and I sort the list, the list itself is getting sorted, but it’s not updating if I don’t assign the list to the new list using Object.assign(newList, oldList)
and then update it by passing to the update state function updateList(newList)
. Here’s my code:
const students= [ { name: "John Done", year: 1, birthdate: "2020-01-24", }, { name: "Another Done", year: 3, birthdate: "2002-02-20", }, { name: "Jack London", year: 2, birthdate: "1800-01-04", }, { name: "Text Name", year: 3, birthdate: "1990-02-24", }, { name: "Name", year: 2, birthdate: "2005-04-01", }, ]; ReactDOM.render(<App students={students} />, document.getElementById('root'));
function App({ students }) { const [studentsList, setStudentsList] = useState(students); const sortByYear = () => { // let sortedstudents = []; // Object.assign(sortedStudents, studentsList); // sorteStudents.sort((a, b) => b.year - a.year); // console.log(sorteStudents); // setStudentsList(sortedStudents); studentsList.sort((a,b) => b.year - a.year)); setStudentsList(studentsList); }; const sortByDates = () => { // let sortedStudents = []; // Object.assign(sortedStudents, studentsList); // sortedStudents.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate)); // console.log(sortedStudents); // setStudentsList(sortedStudents); studentsList.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate)); setStudentsList(studentsList); }; return ( <div className="App"> <div> <label> Sort By </label> <button onClick={() => sortByYear()} > Year </button> <button onClick={() => sortByDates()} > Most Old </button> </div> <Students students={studentsList} /> </div> ); }
Students component
function Students({ students }) { return ( <div> <table> <thead> <tr> <th>Name</th> <th>Year</th> <th>Date of birth</th> </tr> </thead> <tbody> {students.map((student, index) => ( <tr key={index}> <td>{student.name}</td> <td>{student.year.toString()}</td> <td>{student.birthdate}</td> </tr> ))} </tbody> </table> </div> ); }
So here in this way even though the students’ list is getting sorted, the state is not updating, but if I assign the initial list to the new one and then sort it and then update the state it is working.
WORKS
let sortedStudents = []; Object.assign(sortedStudents, studentsList); sortedStudents.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate)); //console.log(sortedStudents); setStudentsList(sortedStudents)
DOES NOT WORK
studentsList.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate)); setStudentsList(studentsList);
So the question is why do I need to assign my studentsList
to the new array, specifically by using Object.assign()
so that setStudentsList()
would update the component’s state? I’ve just started learning React so it’s really confusing me the way how these states actually work.
Similar posts I’ve found
- React Functional Component props does not update
- React functional components props value not updating
- Re render functional component on props change
- React: Passing down props to functional components
Advertisement
Answer
As Brain mentioned: React determines if it should re-render or not based on the equality of previous props to the next props, and previous state to the next state. By mutating the original state array, the previous studentList has referential equality with the updated studentList and react will not detect that it needs to rerender.
So in order to change the list and to React detect the changes, the value of the array needs to be used (mutated), instead of its reference.
As Bergi hinted: alternative that copies the array by value