Redux - State Normalization
Normalization stores entities by ID for efficient updates and lookups. This avoids duplicated data and simplifies updates.
Try it: Normalize users & posts
View source
const { createStore } = Redux;
const initial = {
users: { byId: { 1:{id:1,name:'Ada'}, 2:{id:2,name:'Linus'} }, allIds:[1,2] },
posts: { byId: { 10:{id:10,author:1,title:'Hello'}, 11:{id:11,author:2,title:'World'} }, allIds:[10,11] }
};
function reducer(s=initial, a){
switch(a.type){
case 'user/rename':{
const u = s.users.byId[a.payload.id];
return { ...s, users:{ ...s.users, byId:{ ...s.users.byId, [a.payload.id]:{...u, name:a.payload.name} } } };
}
default: return s;
}
}
const store = createStore(reducer);
function selectPostsWithAuthors(s){
return s.posts.allIds.map(id => {
const p = s.posts.byId[id];
const author = s.users.byId[p.author];
return { id:p.id, title:p.title, authorName: author?.name };
});
}
function render(){
document.getElementById('norm-out').textContent = JSON.stringify(selectPostsWithAuthors(store.getState()));
}
store.subscribe(render); render();
function renameAda(){ store.dispatch({type:'user/rename', payload:{id:1, name:'Ada Lovelace'}}); }
Syntax primer
- Normalize with
{ byId: {..}, allIds:[..] }
to decouple identity from ordering. - Selectors can join across slices to produce view models.