Reputation: 63
I want to sort each column in react. I can do it, but forcing the code, for example if I have this array and display it in a html table, I want when I click id it sort in ascending order, when I click name it sort in ascending order and when click again it sort descending order, i want the same with name and age. And at the same time i want an arrow that if that column is in ascendig is looking up otherwise is looking down.
const USERS = [
{ id: 1, name: "Andy", age: 32 },
{ id: 2, name: "Bob", age: 30 },
{ id: 3, name: "Tom Hulk", age: 40 },
{ id: 4, name: "Tom Hank", age: 50 },
{ id: 5, name: "Audra", age: 30 },
{ id: 6, name: "Anna", age: 68 },
{ id: 7, name: "Tom", age: 34 },
{ id: 8, name: "Tom Riddle", age: 28 },
{ id: 9, name: "Bolo", age: 23 },
];
The way that i can do it is like this, but it's ugly and not practical. And also, when i change the sort state for the arrow, it updates for all the arrow not for the arrow of the column that i clicked
const sortBy = (k) => {
if (k === "id") {
if (sort) {
const res = USERS.sort((a, b) => (a.id > b.id ? 1 : -1));
setDataFilter(res);
setSort(!sort);
console.log(res);
} else {
const res = USERS.sort((a, b) => (a.id < b.id ? 1 : -1));
setDataFilter(res);
setSort(!sort);
console.log(res);
}
} else if (k === "age") {
if (sort) {
const res = USERS.sort((a, b) => (a.age > b.age ? 1 : -1));
setDataFilter(res);
setSort(!sort);
console.log(res);
} else {
const res = USERS.sort((a, b) => (a.age < b.agek ? 1 : -1));
setDataFilter(res);
setSort(!sort);
console.log(res);
}
} else if (k === "name") {
if (sort) {
const res = USERS.sort((a, b) => a.name.localeCompare(b.name));
setDataFilter(res);
setSort(!sort);
console.log(res);
} else {
const res = USERS.sort((a, b) => b.name.localeCompare(a.name));
setDataFilter(res);
setSort(!sort);
console.log(res);
}
} else {
console.log("hmm");
}
};
Upvotes: 1
Views: 86
Reputation: 15530
You may want to have sorting callbacks within a mapping object (by property name or by property type).
Also, do not forget to leverage useMemo()
/ useCallback()
hooks to boost sorting performance through memoizing the sorting output (which may be beneficial for large number of items):
const users = [
{ id: 1, name: "Andy", age: 32 },
{ id: 2, name: "Bob", age: 30 },
{ id: 3, name: "Tom Hulk", age: 40 },
{ id: 4, name: "Tom Hank", age: 50 },
{ id: 5, name: "Audra", age: 30 },
{ id: 6, name: "Anna", age: 68 },
{ id: 7, name: "Tom", age: 34 },
{ id: 8, name: "Tom Riddle", age: 28 },
{ id: 9, name: "Bolo", age: 23 },
],
sortDirection = {
'asc': 1,
'desc': -1
},
numericSorter = propName =>
sortOrder =>
({[propName]:a}, {[propName]:b}) =>
(a-b)*sortDirection[sortOrder],
stringicSorter = propName =>
sortOrder =>
({[propName]:a}, {[propName]:b}) =>
a.localeCompare(b)*sortDirection[sortOrder],
sortMap = {
id: numericSorter('id'),
name: stringicSorter('name'),
age: numericSorter('age')
},
sortUsers = (users, byProp, sortOrder) =>
users.sort(sortMap[byProp](sortOrder))
console.log(sortUsers(users, 'name', 'desc'))
console.log(sortUsers(users, 'age', 'asc'))
.as-console-wrapper{min-height: 100%;}
Upvotes: 1
Reputation: 1448
Try the below code. It checks the type of the sorting key value and choose the sorting method accordingly. I re-used your logic to make it simple for you.
const USERS = [
{ id: 1, name: "Andy", age: 32 },
{ id: 2, name: "Bob", age: 30 },
{ id: 3, name: "Tom Hulk", age: 40 },
{ id: 4, name: "Tom Hank", age: 50 },
{ id: 5, name: "Audra", age: 30 },
{ id: 6, name: "Anna", age: 68 },
{ id: 7, name: "Tom", age: 34 },
{ id: 8, name: "Tom Riddle", age: 28 },
{ id: 9, name: "Bolo", age: 23 },
];
const sortBy = (k, sort) => {
var res;
if( USERS[0] && (typeof USERS[0][k] == 'string')) {
res = sort ? USERS.sort((a, b) => a[k].localeCompare(b[k])) : USERS.sort((a, b) => b[k].localeCompare(a[k]));
} else {
const f = sort ? 1 : -1;
res = USERS.sort((a, b) => (a[k] > b[k] ? f : -f));
}
// setDataFilter(res);
// setSort(!sort);
console.log(res);
}
sortBy('name', 1);
sortBy('age', 1);
sortBy('name', 0);
sortBy('age', 0);
Upvotes: 1