I'm using react and this is my code.
import { useEffect, useState } from "react";
const Test = (props) => {
const [sort, setSort] = useState(1);
const [albums, setAlbums] = useState([
{
"userId": 1,
"id": 1,
"title": "A letter",
"photos": {
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
},
{
"userId": 1,
"id": 2,
"title": "C letter",
"photos": {
"albumId": 2,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
},
{
"userId": 1,
"id": 3,
"title": "B letter",
"photos": {
"albumId": 3,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
},
]);
useEffect(() => {
if (sort == 1) {
setAlbums(albums.sort((a, b) => (a.id > b.id) ? 1 : -1));
} else if (sort == 2) {
setAlbums(albums.sort((a, b) => (a.title > b.title) ? 1 : -1));
} else if (sort == 3) {
setAlbums(albums.sort((a, b) => (a.title < b.title) ? 1 : -1));
}
}, [sort]);
return (
<>
<select value={sort} onChange={e => setSort(e.target.value)} >
<option value='1'>val 1</option>
<option value='2'>val 2</option>
<option value='3'>val 3</option>
</select>
{albums.map((item, key) => {
return (
<p>{item.title}</p>
)
})}
</>
)
}
export default Test;
I'm using react and trying to sort array items with select dropdown. But when I sort it's always one level behind. That means if I select 2 nothing would happen and then select 3 it will get sorted according to value 2. It would be great if someone can give a solution and explain why this happens...
CodePudding user response:
this looks like a good use case for the useMemo hook. try something like this:
const sortedAlbums = useMemo(() => {
if (sort === 1) return albums.sort((a, b) => (a.id > b.id) ? 1 : -1);
...
}, [albums, sort]);
official docs: https://reactjs.org/docs/hooks-reference.html#usememo
CodePudding user response:
Array.prototype.sort
sorts an array in-place—so you can't use it on state. What you need to do is call sort
on a copy of the array, like so.
useEffect(() => {
// deep copy
const copy = JSON.parse(JSON.stringify(albums));
if (sort == 1) {
setAlbums(copy.sort((a, b) => (a.id > b.id ? 1 : -1)));
} else if (sort == 2) {
setAlbums(copy.sort((a, b) => (a.title > b.title ? 1 : -1)));
} else if (sort == 3) {
setAlbums(copy.sort((a, b) => (a.title < b.title ? 1 : -1)));
}
}, [sort]);
Side note: you could refactor that code like so:
useEffect(() => {
const copy = JSON.parse(JSON.stringify(albums));
const conditions = [
(a, b) => (a.id > b.id ? 1 : -1),
(a, b) => (a.title > b.title ? 1 : -1),
(a, b) => (a.title < b.title ? 1 : -1),
];
setAlbums(copy.sort(conditions[sort - 1];
}, [sort]);