Skip to content
This repository has been archived by the owner on Mar 21, 2019. It is now read-only.

Commit

Permalink
add flag to disable onEnter handlers for initial load route resolving
Browse files Browse the repository at this point in the history
  • Loading branch information
michalkvasnicak committed Jan 6, 2016
1 parent 5727553 commit 7f42803
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 14 deletions.
31 changes: 22 additions & 9 deletions src/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 25,8 @@ export default class Router {
constructor(
routes = [],
history,
onTransition = function transitionFinished() {}
onTransition = function transitionFinished() {},
resolveOnLoad = true
) {
invariant(Array.isArray(routes), `Routes should be an array, ${typeof routes} given.`);
invariant(
Expand All @@ -35,6 36,9 @@ export default class Router {

this.routes = instantiateRoutes(routes);

// should onEnter handler run on initial load?
this.resolveOnLoad = resolveOnLoad;

// enable queries means that query parameters can be used directly as objects
this.history = history;

Expand Down Expand Up @@ -84,18 88,27 @@ export default class Router {
if (!location.state) {
this._callEventListeners('changeStart', currentRoute, newRoute, this);

const handlerWrappers = this.handlerWrappers;

// call only on enter handler (initial run)
runRouteHandlers('onEnter', newRoute, handlerWrappers, currentRoute, newRoute, this).then(
() => resolveComponents(newRoute.components).then(
if (this.resolveOnLoad) {
const handlerWrappers = this.handlerWrappers;

// call only on enter handler (initial run)
runRouteHandlers('onEnter', newRoute, handlerWrappers, currentRoute, newRoute, this).then(
() => resolveComponents(newRoute.components).then(
(components) => {
return this._finishRun({ ...newRoute, components }, path, query, true);
},
this._rejectTransition('Route components cannot be resolved')
),
this._rejectTransition('Route onEnter handlers are rejected.')
);
} else {
resolveComponents(newRoute.components).then(
(components) => {
return this._finishRun({ ...newRoute, components }, path, query, true);
},
this._rejectTransition('Route components cannot be resolved')
),
this._rejectTransition('Route onEnter handlers are rejected.')
);
);
}
} else {
this._currentRoute = newRoute;

Expand Down
26 changes: 23 additions & 3 deletions src/createRoutex.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 14,30 @@ import {
changeStart
} from './actions';


export default function createRoutex(routes, history, onTransition) {
/**
* Creates routex instance and returns store, reducer and router insance
*
* @param {Array} routes
* @param {Object} history
* @param {?Function} onTransition
* @param {?Boolean} resolveOnLoad should on enter handler run on initial load?
* @returns {{router: Router, store: store, reducer: {router: reducer}}}
*/
export default function createRoutex(routes, history, onTransition, resolveOnLoad) {
const initialReducerState = { state: 'INITIAL', route: null };
const router = new Router(routes, history, onTransition);
const args = [];

if (arguments.length >= 4) {
args.push(onTransition, resolveOnLoad);
} else {
if (typeof onTransition === 'boolean') {
args.push(undefined, onTransition);
} else {
args.push(onTransition, undefined);
}
}

const router = new Router(routes, history, ...args);

const store = (next) => (reducer, initialState) => {
const modifiedInitialState = initialState;
Expand Down
50 changes: 48 additions & 2 deletions test/Router.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 30,15 @@ describe('Router', () => {

describe('#listen()', () => {
it(
'starts listening to pop state events and replaces state on initial and replaces state if undefined',
'starts listening to pop state events and replaces state on initial and replaces state if undefined (resolveOnLoad = true, run onEnter handlers)',
(done) => {
const changeStart = spy();
const changeSuccess = spy();
const onEnter = spy();
const history = createMemoryHistory();

const router = new Router(
[{ path: '/', component: 'A' }],
[{ path: '/', component: 'A', onEnter }],
history,
(err, resolvedRoute) => {
try {
Expand All @@ -53,6 54,7 @@ describe('Router', () => {

expect(changeStart.called).to.be.equal(true);
expect(changeSuccess.calledOnce).to.be.equal(true);
expect(onEnter.called).to.be.equal(true);

done();
} catch (e) {
Expand All @@ -70,6 72,50 @@ describe('Router', () => {
}
);

it(
'starts listening to pop state events and replaces state on initial and replaces state if undefined (resolveOnLoad = false, do not run onEnter handlers)',
(done) => {
const changeStart = spy();
const changeSuccess = spy();
const onEnter = spy();
const history = createMemoryHistory();

const router = new Router(
[{ path: '/', component: 'A', onEnter }],
history,
(err, resolvedRoute) => {
try {
expect(err).to.be.equal(null);
expect(resolvedRoute).to.be.an('object');
expect(resolvedRoute.pathname).to.be.equal('/');
expect(resolvedRoute.fullPath).to.be.equal('/');
expect(resolvedRoute.components).to.be.eql(['A']);

expect(history.replaceState.calledOnce).to.be.equal(true);
expect(history.replaceState.getCall(0).args[0]).to.be.equal(resolvedRoute);
expect(history.replaceState.getCall(0).args[1]).to.be.equal('/');

expect(changeStart.called).to.be.equal(true);
expect(changeSuccess.calledOnce).to.be.equal(true);
expect(onEnter.called).to.be.equal(false);

done();
} catch (e) {
done(e);
}
},
false
);

spy(history, 'replaceState');

router.addChangeStartListener(changeStart);
router.addChangeSuccessListener(changeSuccess);

router.listen();
}
);

it(
'starts listening to pop state events and calls not found listeners if current location is not mapped to route',
(done) => {
Expand Down

0 comments on commit 7f42803

Please sign in to comment.