17

I have been trying to learn how to better structure my Redux stores and stumbled upon this lesson by Dan.

https://egghead.io/lessons/javascript-redux-normalizing-the-state-shape#/guidelinesModal

Although I understand how to go about normalizing my data in this way, I do not understand the motivation behind it. Particularly, I have two questions.

  1. Why wont simple arrays be sufficient? Dan mentions - "In complex apps, we might have more than a single array and todos with the same IDs in different arrays might get out of sync". I did not understand this, may I have an example? The only benefit I see from using an object is improved efficiency as we do not need to map over the entire array, in case I want to delegate a certain todo to another reducer.

  2. Why do we need to maintain a list of allIds? Why maintain this additional state, when we can easily map over the list of all todos and obtain it?

I know that normalizr does this for us, but why should we normalize in the first place? Does it make sense to normalize even if the responses are not deeply nested?

Edit 1:

Thanks for your answer, Christopher.

Let us assume that your state tree looks like this

{
    user: {
        byId: {
            1: {
                id: 1,
                name: 'Buy stuff'
               }, 
            2: {
                id: 2,
                name: 'Yeah'
               }
            }
        },
        allIds: [1, 2],
        subscribedIds: [5],
    }
    department: {
        byId: {
            5: {
                id: 5,
                name: 'Sell Stuff'
            }
        },
        allIds: [5],
        subscribedIds: []
    }   
}

I do not see the benefit of having an object in place of an array here. I could as well have selectors which would fetch the subscribed todo by ID from departments, even if it is an array. It seems my understanding of the concept is a bit deficient. Could you please elaborate?

Karthik Iyengar
  • 584
  • 1
  • 4
  • 14
  • 2
    Yeah. Regarding your last question, if understand you, just having an array of shallow objects rather than an object hierarchy would work just fine. But if you end up with *lots* of items in the arrays, and you are regularly doing a "find this id" operation, each array lookup is O(N). Putting your objects into a hash structure instead makes lookups O(1)... significantly faster. – Christopher Davies Jul 06 '16 at 13:52
  • Perfect! Thank you. – Karthik Iyengar Jul 06 '16 at 14:00
  • 1
    For anyone looking for more literature on the topic, you can refer to http://redux.js.org/docs/FAQ.html#organizing-state-nested-data and the articles linked there. – Karthik Iyengar Jul 06 '16 at 17:05
  • 1
    Regarding your question about array vs object, if you're doing a lookup by id, it'll be a lot more performant in object form vs searching an array. Depends on how often you have to do a lookup. – Christopher Davies Nov 05 '16 at 21:57

2 Answers2

18
  1. "In complex apps, we might have more than a single array and todos with the same IDs in different arrays might get out of sync."

You may have a TODO (say with id 1) which is in a "User's TODOs" list and a "Department's TODOs" list at the same time, for example. And then if a user updates her todo, that TODO should also be updated in the "Department's TODOs" list. If your data is normalized, the TODO will be updated in both places (well, there will really only be one instance of the TODO which is simply referred to from multiple places). But if it's not normalized, the department will have a stale copy of the todo.

  1. "Why keep a list of all ids?"

I think you're right, honestly. If you're going to bother normalizing, then duplicating a list of IDs kind of seems to run counter to that effort.

Anyway, I think the case for normalizing data in React probably mirrors the case for normalizing data in general (e.g. in databases). It's a bit more effort up front, but the flexibility it gives you is generally worth it.

Also, I don't always normalize my React code, but I find that not normalizing ends up making my code sloppier over time. I just become less disciplined. I guess it's like the broken-window effect. In non-normalized code, I just start throwing values into places they really probably shouldn't be simply out of convenience.

Christopher Davies
  • 4,461
  • 2
  • 34
  • 33
12

Why do we need to maintain a list of allIds? Why maintain this additional state, when we can easily map over the list of all todos and obtain it?

Storing an array of IDs allows us to define an order for the items. While JS engines now have a fairly standardized process for iterating across keys in an object, you shouldn't rely on that to define ordering.

Answer thanks to markerikson

Community
  • 1
  • 1
joshhunt
  • 5,197
  • 4
  • 37
  • 60
  • But what would this presumed ordering be with respect to? The name `allIds` doesn't quite provide that context...if it did it would be something like `allIdsSortedByName`, which arguably strays from the concept of 'normalized' – strider Nov 11 '17 at 18:03
  • 1
    It could be to signify a concept like `allIdsSortedInTheOrderAUserPutThemIn`. Something like `byName` could be inferred at run time, but if there's a drag-and-drop interface of some sort then the order is idiosyncratically defined by the user, and not based on any aspect of each entity. – Luke Griffiths Feb 23 '18 at 16:28