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.