Redux - Why normalize?

2019-03-18 09:11发布

问题:

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?

回答1:

  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.



回答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?

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