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_START
action is fired usingaddDependencyStart
action creatorADD_DEPENDENCY_START
workflow fromdependency.middleware
is fired- this, in turn, fires off
installDependency
fromdependencies.service
dependencies.reducer
updates the state for that project to indicate that the new dependency is installinginstallDependency
spawns a child shell process to actually run yarn add lodash or whatever- the dependency finishes installing, which resolves the Promise returned by
installDependency
and 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_FINISH
action using theaddDependencyFinish
action creator- if
installDependency
orloadProjectDependency
fail, anADD_DEPENDENCY_ERROR
action is dispatched using theaddDependencyError
action creator dependencies.reducer
will handleADD_DEPENDENCY_FINISH
orADD_DEPENDENCY_ERROR
accordingly 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