I have an app which is very similar to instagram, but instead of having one main feed, the user can have multiple feeds based on the events he/she attends. I'm using redux for the state management and currently I have these reducers:
- feed
- people
- schedule
- user
- navigation
My feed reducer looks like:
{
allEvents: [],
event: {
id: 123,
name: 'Foo'
},
items: [
{
id: 23,
imageUrl: 'http://img.com/foo',
likes: [{ id: 1, user: {...} }, { id: 2, user: {...} }],
comments: [{ id: 1, text: '...', user: {...} }, { id: 2, text: '...', user: {...} }]
}
]
}
So my state structure currently looks like:
{
feed,
people,
schedule,
user,
navigation
}
But at the moment every time the user changes current event the whole feed state is replaced by a new state for that particular event, so if the user comes back to the previous event the whole feed needs to be fetched again, same is with people reducer and schedule, which depends on the event. Also user has it's own profile feed which shows user's feed items. And in order to have this feed I would need to duplicate what I have in the current feed reducer, so I thought it would be better to have multiple feeds, inside event reducer.
I was wondering if the state structure like this wouldn't be better:
{
events: {
items: [
feed,
people,
schedule
]
}
user,
navigation
}
Then I read redux#815 or redux#994 that it's not the best way to nest reducers. Should it look more or less like:
{
feed: {
feedIds: [23, 24, 25],
byId: {
23: {
items: [123, 124, 125]
}
}
},
items: {
itemsIds: [123, 124, 125, 126, 127],
byId: {
124: {
id: 124,
image: 'http://img.com ',
likes: [1, 2, 3]
}
}
},
likes: {
likesIds: []
},
events: {
eventIds: [1, 2, 3],
byId: {
1: {
id: 1,
name: 'TYW Croatia w34'
feedId: 23,
peopleId: 12,
scheduleId: 1
}
}
},
people: {...}
}
What's the best practice in this case and which way is the most performant?
A normalized structure, like your last example, is definitely both a best practice and more performant. The state is flatter, so updates are more targeted and affect fewer unrelated objects; items can be easily looked up by ID as needed; and the update logic will generally be simpler. Also, this allows you to pass item IDs to connected child components, which then look up their own data based on that ID, and they will only need to re-render when their own data changes. Finally, it works well for caching data.
You might want to read through some of these articles on Redux performance for more information, particularly High Performance Redux. You may also want to read some of the discussion at https://github.com/reactjs/redux/issues/1824#issuecomment-228585904.
edit:
As a follow-up, I recently added a new section to the Redux docs, on the topic of "Structuring Reducers". In particular, this section includes chapters on "Normalizing State Shape" and "Updating Normalized Data".