score:5

Accepted answer

yeah, what you're describing is what you have to do if you store normalized state and then want your components to consume an array.

usually, my state will be something like this:

users: {
  byid: {
    // map of objects keyed by id
  },
  ids: [//array of ids],
}

note that i'm keeping ids around to keep track of the order the items were returned from the server; that may or may not be necessary depending on the use case. you may be able to just store the object and use object.keys if the order is not important (probably because you end up sorting by some other criteria).

typically, the most consumable form of the data will be an array, so you would define a selector to get the users. following the pattern of colocating reducers and selectors, you would have

// user reducer
export const getusers = (state) => state.ids.map(id => state.byid[id])

and

// root reducer
import users, * as fromusersreducer from './users

const reducer = combinereducers({
  users,
})

export const getusers = (state) => fromusersreducer(state.users)

and then your container

import { connect } from 'react-redux'
import { getusers } from 'reducers/root'
import userscomp from './users

const mapstatetoprops = (state) => ({
  users: getusers(state),
})

export default connect(mapstatetoprops)(userscomp)

in terms of whether this conversion is a reasonable cost or not, it depends on the use case. where normalized state shape gets to be really important is when you're data can be edited, or your data is related to other pieces of data (getting all posts from a user etc.). if, however, all you're doing is getting a list of data and all you ever do with it is just display that list, then normalizing is probably not necessary.

if you end up needing to add more complex operations for the data down the line, it is easy to switch assuming you are being strict about only accessing state via selectors. normalized data is generally seen as a best practice simply because you generally are going to end up doing more complex things with your data where having a normalized shape is advantageous. but it's not a hard rule or anything; there are cases where it's not needed for sure.

the only real costs you are looking at here is

  1. code to perform the normalization/denormalization.
  2. performance hit if your lists are very long, having to denormalize on every render of a container.

you can mitigate the performance hit pretty easily using reselect. this is oftentimes not necessary. in terms of the extra code, it's basically the same sort of stuff over and over again, so it can be pretty easy to abstract, and the code itself is really not complicated anyways. it's a lot less complicated than reducer/selector code would be in a complex app if everything were stored as arrays.


Related Query

More Query from same tag