State as array of objects vs object keyed by id

Think of the app’s state as a database.

That's the key idea.

1) Having objects with unique IDs allows you to always use that id when referencing the object, so you have to pass the minimum amount of data between actions and reducers. It is more efficient than using array.find(...). If you use the array approach you have to pass the entire object and that can get messy very soon, you might end up recreating the object on different reducers, actions, or even in the container (you dont want that). Views will always be able to get the full object even if their associated reducer only contains the ID, because when mapping the state you'll get the collection somewhere (the view gets the whole state to map it to the properties). Because of all of what i've said, actions end up having the minimal amount of parameters, and reducers the minimal amount of information, give it a try, try both methods and you'll see the architecture ends up more scalable and clean using IDs if collections do have ID.

2) The connection to the API should not affect the architecture of your storage and reducers, that's why you have actions, to keep the separation of concerns. Just put your conversion logic in and out of the API in a reusable module, import that module in the actions that use the API, and that should be it.

3) I used arrays for structures with IDs, and these are the unforeseen consequences i've suffered:

  • Recreating objects constantly throughout the code
  • Passing unnecessary information to reducers and actions
  • As consequence of that, bad, not clean and not scalable code.

I ended up changing my data structure and rewriting a lot of code. You have been warned, please don't get yourself in trouble.

Also:

4) Most collections with IDs are meant to use the ID as a reference to the whole object, you should take advantage of that. The API calls will get the ID and then the rest of the parameters, so will your actions and reducers.


Q1: The simplicity of the reducer is a result of not having to search through the array to find the right entry. Not having to search through the array is the advantage. Selectors and other data accessors may and often do access these items by id. Having to search through the array for each access becomes a performance issue. When your arrays get larger, the performance issue worsens steeply. Also, as your app becomes more complex, showing and filtering data in more places, the issue worsens as well. The combination can be detrimental. By accessing the items by id, the access time changes from O(n) to O(1), which for large n (here array items) makes a huge difference.

Q2: You can use normalizr to help you with the conversion from API to store. As of normalizr V3.1.0 you can use denormalize to go the other way. That said, Apps are often more consumers than producers of data and as such the conversion to store is usually done more frequently.

Q3: The issues you'll run into by using an array are not so much issues with the storage convention and/or incompatibilities, but more performance issues.