I have the following parent component. It makes use of dynamicSort, a custom sort function for an array of objects that returns a sorted array of objects by the specified key. I have confirmed that the sort function works:
import React, { useState, useEffect } from 'react';
import { dynamicSort } from '../helpers';
import Container, ChildHeader, Childbody, Spinner, etc...
const Parent = () => {
const [listItems, setListItems] = useState([]);
useEffect(() => {
// fetch list items and set them here on component mount
// this works currently
}, [])
const sortList = column => {
setListItems(prev => dynamicSort(prev, column, 'asc'));
};
return (
<Container>
<ChildHeader
sortList={sortList}
/>
<ChildBody>
{listItems !== [] ? (
listItems.map(item => {
return (
<ChildRow
key={item.id}
rowItem={item}
/>)
})
) : (
<Spinner />
)}
</ChildBody>
</Container>
);
};
export default Parent;
Inside of childHeader, I call the prop sortList on a heading click like this:
const ChildHeader = ({ sortList }) => {
return (
<HeaderContainer>
<Column1
onClick={() => {
sortList('Column1'); // This should sort and reset the state of the list in the parent
}}
>
{'Column Label'}
</Column1>
// More columns...
</HeaderContainer>
);
};
export default ChildHeader;
I have confirmed that handler is called when the child component is clicked. But for some reason the state does not update on the parent list. The even weirder thing to me is that if I change the sortList method in the parent to the following code, the list updates on child click.
const sortList = column => {
setListItems(prev => prev.slice(0, 3); // Using slice instead of my custom sort method
};
This makes me think that there is something wrong with my sort method. I have confirmed that the sort method does return an array of objects and that it is sorting correctly. Any have a clue what’s happening? I’ll include the sort method below just for kicks:
export const dynamicSort = (list, column, direction) => {
const compare = (a, b) => {
switch (column) {
case 'Column1':
if (direction === 'asc') {
if (a.key1 > b.key1) {
return 1;
}
if (a.key1 < b.key1) {
return -1;
}
return 0;
}
if (direction === 'desc') {
if (a.key1 < b.key1) {
return 1;
}
if (a.key1 > b.key1) {
return -1;
}
return 0;
}
// More cases following below
default:
return null;
}
};
return list.sort(compare); // This does return an array of objects sorted correctly by key
}
>Solution :
Because you’re not actually updating state. You’re mutating state. According to the documentation for sort:
The
sort()method sorts the elements of an array in place and returns the reference to the same array, now sorted.
So you’re updating state to the same array reference, which means React has no way to know that state has been modified in any way.
Probably the simplest approach would be to modify your dynamicSort function to sort a new array reference, which could be as simple as destructuring the array before sorting it:
return [...list].sort(compare);