Let's walk through adding a new dependency - I think that's complex enough without being too much to grasp:
- User clicks Add to Project after searching for and finding a dependency
ADD_DEPENDENCY_STARTaction is fired usingaddDependencyStartaction creatorADD_DEPENDENCY_STARTworkflow fromdependency.middlewareis fired- this, in turn, fires off
installDependencyfromdependencies.service dependencies.reducerupdates the state for that project to indicate that the new dependency is installinginstallDependencyspawns a child shell process to actually run yarn add lodash or whatever- the dependency finishes installing, which resolves the Promise returned by
installDependencyand moves to the next step of the middleware,loadProjectDependency loadProjectDependency(fromread-from-disk.service) loads the specifics about the newly installed dependency and dispatches them as anADD_DEPENDENCY_FINISHaction using theaddDependencyFinishaction creator- if
installDependencyorloadProjectDependencyfail, anADD_DEPENDENCY_ERRORaction is dispatched using theaddDependencyErroraction creator dependencies.reducerwill handleADD_DEPENDENCY_FINISHorADD_DEPENDENCY_ERRORaccordingly and update the project's state
Since middleware are constructed like
const middleware = store => next => action => {
/* ... */
}You can dispatch actions in one of two ways:
// dispatch an action to the beginning of the middleware chain
store.dispatch(/* ACTION */);
// dispatch an action AND SKIP ANY MIDDLEWARE BEFORE AND INCLUDING THIS ONE
// * this helps to avoid infinite looping in case you're dispatching an
// action you're also handling
next(/* ACTION */);So all the next() calls in middleware are essentially just store.dispatch() (this tripped me up for a while).
To try and summarize:
- actions - tell us that something needs to happen
- reducers - update Redux state according to actions
- middleware - fire off side-effects of actions
- services - utility methods for interacting with the host OS