Redux: button click potentially fires 3 action for different reducers
I was wondering if when the user clicks “Save” it is better to call a function in the List component that calls “addNew” and “deleteB” and finally “editSave” to only update the state for the “editing” state property.


I would avoid this. Ideally, all your logic should live either the reducer or the thunk, NOT in components. This way, your logic is in one place, are easily and uniformly testable, and are not affected by things such as re-implementation of the UI (i.e. changing of components, replacing the UI library, etc).

Reducers are just pure functions - they take in old state and an action, and they return new state. As long as you follow that basic principle, you're good. When you call a reducer from another reducer, you're effectively just composing reducers - which isn't a strange concept in Redux. So it's not weird to have something like this:

export const add = (state, action) =&gt; { ... }

export const edit = (state, action) =&gt; { ... }

export const delete = (state, action) =&gt; { ... }

export const someWeirdCaseOfAddEditDelete = (state, action) =&gt; {
  if(action.type === state.editing.type) {
    return edit(state, action)
  } else {
    const intermediateState = add(delete(state, action), action)
    const finalState = doMoreStuffWith(intermediateState, action)
    return finalState
  }
}


As an added bonus, when the time comes when someWeirdCaseOfAddEditDelete starts to deviate from your regular add, edit and delete, you can simply replace its implementation and its tests without having to meddle with the other three reducers.



To address your concerns in the comments:


  I thought that was an anti-pattern because it's like dispatching an action inside a reducer that got executed from an action.


Calling dispatch in a reducer is the antipattern. But composing functions (i.e. breaking up your reducer into subfunctions that deal with specific parts of the state) is totally fine.

It may be easier to wrap your head around the idea by dropping the assumption that the common operation is a reducer. Think of it as just a common utility function:

const thatCommonFunction = (somePartOfTheState) =&gt; ({
  thatOnePropertyYouNeedToChange: { ... }
})

const reducer1 = (state, action) =&gt; ({
  ...state,
  ...thatCommonFunction(state.some.part)
})

const reducer2 = (state, action) =&gt; ({
  ...state,
  ...thatCommonFunction(state.some.part)
})



  Every time I call "deleteB" or "add" from "someWeirdCaseOfAddEditDelete" the state will update, before returning the intended "finalState".


If the state updates before all of your reducers return the new state to Redux, then there's something wrong with your code.

Redux receives the updated state only after it runs through all the reducers. The state should never update while execution is still in the reducer.

Under the hood, at the very basic, Redux does something like this:

const createStore = (rootReducer, initialState = {}) =&gt; {
  let currentState = initialState;
  const subscriptions = [];

  return {
    dispatch(action) {
      // This part is where control is handed over to your reducers.
      currentState = rootReducer(currentState, action);

      // Only after the line above should your state be updated.

      // After that one line, the UI is informed of the update.
      subscriptions.forEach(s =&gt; s(currentState))
    },
    subscribe(fn) {
      subscriptions.push(fn)
    }
  })
}