How to handle my redux store with Lodash and Normalizr?

3k views Asked by At

I just don't get it. This is all alchemy and the promises of making frontend development easier obscure the various ingredients that you have to mix just right for those promises to hold true. Either I'm mixing the wrong things together, or my chants are off tune. I don't know.

This is going to be a mix of questions. Maybe typing it all out will help me figure out where I seem to be getting this all wrong.

I'm using normalizr to flatten out my API response. It took me a while to even figure out I should use something like that. Fighting arrays of objects in redux was fun for a while, but now I'm on the flattening responses stage of the journey. So my API response returns a list of people and normalizr breaks it down into the store like:

people: { 
  people: { 
    entities: {
      1: { id: 1, name: "jim" },
      2: { id: 2, name: "billy" }
    },
    results : [ 1 , 2 ]
  }
} 

Why is people two keys deep? I don't know. I couldn't get the reducer to work any other way. I'm going by examples I saw people using. Here's my reducer (simplified to show the relevant piece):

case "GET_PEOPLE": {
  return  {...state, people: action.payload}
}

Okay well that works fine. great even! Until I want to add more people from the API. See, for some reason if I drop more people into this reducer it just replaces everything instead of adding them. Okay so I'm doing this wrong. A little bit more research brings up this thing called Lodash which has a merge function. Perfect! I'm not merging the results in the store, I must be replacing them (or that's what it seems). So let's use Lodash in the reducer to merge results instead of replace them.

case "SET_PEOPLE": {
  return  merge({}, state, action.payload)
}

Alright so it looks fine, and it works! Results are merged instead of replaced. And this way has the added benefit of not needing to add that extra people key in the reducer. So I actually went and changed a lot of my code to not use that extra people key. Until I find out Lodash is duplicating keys in the result array.

A lot of this stuff seems really new. It seems like people are still figuring out the "right" way to do things, and what tools are most effective. At least that what it seems like from scouring various guides, READMEs, and documentation. They all tell you to use a different approach (and they've only been written months apart at most).

I think pentagrams, candles, and chanting would be as effective at this point, but I'm holding out hope someone can help me with the right ingredients here. I'm using React, which led to needing Redux, which led to needing Normalizr, which apparently leads to needing Lodash. Is that correct? Am I on the right path there? If not, what are the minimum set of tools to make frontend state management a bearable process. Conceptually I love what I'm working with but there's so many gotchas it's ridiculous.

The reducer:

export default function reducer(state={
    people: {
        entities : {
          people: {
            0 : {
              name : ''
            }
          }
        },
        result : [0,]
    }
  }, action) {
  switch (action.type) {
    case "GET_PEOPLE": {
      const newpPeople = {...state.people, ...action.payload };
      console.log(state.people)
      console.log(action.payload)
      console.log(newpPeople)
      return {...state, people : newpPeople};
    }
    default :
      return state
  }
}

This first console log is the state after the reducer has been used once. it has the initial set of people that i've state to the store:

{ 
    entities: { 
      people : { 
        1 : { id: 1, name: "jim" },
        2 : { id: 2, name: "billy" }
      }
    },
    result : [ 1, 2 ]
}

The second console log will be the payload of new people to be added:

{ 
    entities: { 
      people : { 
        7 : { id: 7, name: "sally" },
        8 : { id: 8, name: "ana" }
      }
    },
    result : [ 7, 8 ]
}

Then the third console log should be the two states combined? But it just repeats the last one with sally and ana, and overwrites everything else.

1

There are 1 answers

6
ZekeDroid On BEST ANSWER

Haha props for the funny bits. You're definitely on the right path and conceptually makes sense, the implementation definitely takes some getting used to. I think you're getting confused because of the ES6 features. For example, when you use the spread operator (...), it will dump all key:value pairs into that new object you're creating, but if you then add the people key, it will replace the previous one. No need for lodash really.

The correct to have done that would have been to do:

const newPeople = { ...state.people, ...action.payload };
return { ...state, people: newPeople };

As for your second bit of confusion, you need two people because the first is the name of the reducer, as defined wherever you define them for use by your store (likely something called indexReducers). The second people is because that particular reducer has a key called people, which isn't really necessary assuming the entire state of that reducer IS your people.

Lmk if more things need clearing up.