Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting array of objects in Redux reducer

I am trying to sort an array like this (my state):

[
  {
    name:"Aenean in justo ante"
  },
  {
    name:"Phasellus viverra mattis dolor"
  }
]

I dispatch an action to the reducer: (part of reducer)

case 'SORT_COLLECTION':
  return state.sort(function(a, b) {
    var nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
    if (nameA < nameB) {
      return -1;
    }
    if (nameA > nameB) {
      return 1;
    }
    return 0;
  })

but it does not work. Could somebody tell me where the mistake is?

like image 961
Mac Avatar asked Aug 30 '17 14:08

Mac


2 Answers

The sorting function should work fine. But you should not mutate the original state in the reducer. You can create a copy of the state array by calling state.slice() before sorting.

case 'SORT_COLLECTION':
  return state.slice().sort(function(a, b) {
    var nameA = a.name.toLowerCase(),
      nameB = b.name.toLowerCase()
    if (nameA < nameB)
      return -1
    if (nameA > nameB)
      return 1
    return 0
  })

Of course, you can define a simpler sort function as well.

const state = [{name:'foo'},{name:'bar'},{name:'baz'}]
const sortByKey = key => (a, b) => a[key] > b[key] ? 1 : -1
const sorted = state.slice().sort(sortByKey('name'))
console.log(`state=${JSON.stringify(state)}\nsorted=${JSON.stringify(sorted)}`)
like image 79
Håken Lid Avatar answered Oct 01 '22 15:10

Håken Lid


You need to do:

state.slice().sort(...

As sort() changes the original array by reordering references (mutates it) which is a "no go" for redux store. slice() first does a shallow copy meaning only references are copied and it is fast (unless it contains primitives in which case they will be copied, but it will still be fast) and then those new references are moved around by sort().

NOTE: you still can not change the objects within the array, but luckily sort does not change them.

like image 30
Orhan Avatar answered Oct 01 '22 14:10

Orhan