How to reuse Redux reducer logic for multiple instances of the same data type?

Viewed 586

Say I have an application for keeping track of university courses. Each course has some attributes like name time notes id. In the application, the user can add/remove courses and edit their attributes. How would I structure a redux store for this?

My first thought is to make the state a mapped object like so:

interface Course {
  id: string;
  name: string;
  time: string;
  notes: string;
}

interface StoreState {
  [id: string]: Course;
}

where each entry in the state corresponds to a course instance. Then, when the user adds a new course, I add a new entry to the state

const slice = createSlice({
  name: 'courses',
  initialState: {},
  reducers: {
    addCourse: (state, action) => {
      state[action.payload.id] = {
        id: action.payload.id,
        name: action.payload.name,
        ...
        ...
      }
    },
    updateNotes: (state, action) => {
      state[action.payload.id].notes = action.payload.notes
    }
    ...
    ...
  }
})

This is not ideal because I have to redundantly use the course id in every case reducer to update the correct course. I'd like to have a state object in the store for each course and write my case reducers like this:

    updateNotes: (state, action) => {
      state.notes = action.payload.notes
    }

I shouldn't have to worry about which course I'm updating because they all function the same way. Is there a way to dynamically create states for each course that share the same reducer logic?

2 Answers

Looking at this I think what you concerned about is ending up with a data structure where ID is both a key and a property in your stored data and this breaks the idea that the data store in Redux should be the minimum dataset without any repetition.

The solution to this is to only store the ID as the key and the use a library called Reselect to merge the key back into the data when you take it from the store.

https://github.com/reduxjs/reselect

Related