Created
January 12, 2017 02:04
-
-
Save petemill/a1bafcb34e28476905edffdba38d482f to your computer and use it in GitHub Desktop.
Returns a class which handles running and cancelation of redux sagas when a route is entered and left
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
declare var System:any; | |
import { getAsyncInjectors } from './asyncInjectors'; | |
export default function LazyLoadReduxRouteFactory(store: any) { | |
const { injectReducer, injectSagas, removeSagas } = getAsyncInjectors(store); | |
return class LazyLoadReduxRoute { | |
reducerName: string; | |
getComponentModule: Function; | |
getReducerModule: Function; | |
getSagaModule: Function; | |
loadedSagaTasks: []; | |
getComponentCustom: ?Function; | |
onEnterCustom: ?Function; | |
onLeaveCustom: ?Function; | |
constructor({ reducerName, getComponentModule, getReducerModule, getSagaModule, getComponent, onEnter, onLeave, ...routeProps }: Object) { | |
//validate | |
if (typeof getComponentModule !== 'function') { | |
throw new Error('Must pass param getComponentModule as function to create a LazyLoadReduxRoute'); | |
} | |
//save details to instance | |
this.getComponentModule = getComponentModule; | |
//process optional args | |
if (typeof getReducerModule === 'function') { | |
if (typeof reducerName !== 'string') { | |
throw new Error('When providing a reducer, must also provide a reducerName'); | |
} | |
this.reducerName = reducerName; | |
this.getReducerModule = getReducerModule; | |
} | |
if (typeof getSagaModule === 'function') { | |
this.getSagaModule = getSagaModule; | |
} | |
//allow events we handled to have custom logic | |
if (typeof getComponent === 'function') { | |
this.getComponentCustom = getComponent; | |
} | |
if (typeof onEnter === 'function') { | |
this.onEnterCustom = onEnter; | |
} | |
if (typeof onLeave === 'function') { | |
this.onLeaveCustom = onLeave; | |
} | |
//expose any other route properties caller provides | |
Object.assign(this, routeProps); | |
} | |
async getComponent(nextState: any, cb: Function) { | |
//get modules in paralell | |
const ops = [ this.getComponentModule() ]; | |
//reducer is optional | |
if (this.getReducerModule) { | |
ops.push( | |
this.getReducerModule() | |
.then(reducerModule => injectReducer(this.reducerName, reducerModule.default)) | |
); | |
} | |
const [ componentModule ] = await Promise.all(ops); | |
cb(null, componentModule.default); | |
} | |
async onEnter(nextState: any, replace: Function) { | |
//should we be loading sagas | |
if (this.getSagaModule) { | |
//sanity check, should not have loaded tasks yet (or still from previous visit to page) | |
if (!this.loadedSagaTasks) { | |
//load saga module | |
const sagas = await this.getSagaModule(); | |
//remember sagas and saga-tasks, for cancelling later | |
this.loadedSagaTasks = injectSagas(sagas.default); | |
} | |
//handle sagas not previously unloaded | |
else { | |
console.error('sagas were already loaded', { tasks: this.loadedSagaTasks }); | |
} | |
} | |
//custom route onEnter | |
if (this.onEnterCustom) { | |
this.onEnterCustom(nextState, replace); | |
} | |
} | |
onLeave(prevState: any) { | |
//custom route onLeave | |
if (this.onLeaveCustom) { | |
this.onLeaveCustom(prevState); | |
} | |
//cancel running tasks, if any | |
if (this.loadedSagaTasks) { | |
this.loadedSagaTasks.forEach(saga => saga.cancel()); | |
//remove reference to cancelled tasks | |
delete this.loadedSagaTasks; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment