Mac
Mac

Reputation: 151

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?

Upvotes: 6

Views: 18533

Answers (4)

H&#229;ken Lid
H&#229;ken Lid

Reputation: 23064

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)}`)

Upvotes: 18

Orhan
Orhan

Reputation: 1475

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.

Upvotes: 4

Dan Mason
Dan Mason

Reputation: 2327

The Array.prototype.sort method requires you to return an integer or a boolean.

The below shows how to order in either direction.

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

console.log("Alphabetical:", arr.sort((a,b) => a.name > b.name));
console.log("Reversed:", arr.sort((a,b) => a.name < b.name));

Upvotes: 0

LowCool
LowCool

Reputation: 1411

if you are using es6 you can try like this state.sort((a,b) => a.name - b.name);

Upvotes: 0

Related Questions