Goal
Iterate upon Thunk for Redux actions with Observables, following a less-is-more philosophy by introducing additional complexity strictly where necessary. In other words, rely on subset of Thunk, "promise actions," for 90% of an application, then leverage Observables to orchestrate true side effects.
Install
npm iRun
npm startThunk -> Observable Progression
part1-standard-thunkpart2-streamlined-thunkpart3-streamlined-reducerpart4-observable-setuppart5-observable-orchestrationpart6-observable-enhancements
Futher Optimizations
-
Instead of letting async actions contain a promise (active request), let them contain a promise factory and promise factory arguments--thereby "purifying" them, making testing easier:
export const search = (query) => ({ type: actionTypes.SEARCH, promise: { call: youtubeApi.search, args: [query] } });
Then, modify
async-actions#ResultAsyncActionto perform the actual promise instantiation. -
Instead of having API helpers (
api/youtube.js) return simple promises, have them return an Observable wrapped around a cancelable XHR request, such asRx.Observable.ajax(). This will result in browser level request cancelation of abandoned async actions for free.- Another option is to create a custom Observable wrapper around any cancelable XHR library of choice.
- Any Observable can be converted to a promise to retrofit within standard promise/async-await code using
RxJS.Observable.toPromise().
-
Implement error handling using the
meta.errorobject of failed async actions. -
Customize action API's and action reduction within
async-actions.jsandAsyncReducer.jsto fit the needs of a given given app. -
Research a way to avoid the extra
handleSearchEpicwhile still achieving request cancelation.
Alternatives
-
Eliminate Thunk and promise middleware and use Redux-Observable Epics exclusively (more traditional Redux-Observable approach).
-
mobx-state-tree takes the Observables approach further, creating Observables from state properties in addition to actions. This allows notification of state change on a fine grained level, as opposed to strictly reacting to system events.