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

Commit

Permalink
run onEnter handlers on initial load
Browse files Browse the repository at this point in the history
  • Loading branch information
michalkvasnicak committed Jan 4, 2016
1 parent 26f2733 commit 85ef5d0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 66 deletions.
123 changes: 58 additions & 65 deletions src/Router.js
Original file line number Diff line number Diff line change
@@ -1,5 1,5 @@
import Route from './Route';
import { normalizeRouteDefinition, runRouteHandlers } from './utils/routeUtils';
import { normalizeRouteDefinition, runRouteHandlers, resolveComponents } from './utils/routeUtils';
import { resolveWithFirstMatched } from './utils/routerUtils';
import { Actions } from 'history';
import invariant from 'invariant';
Expand Down Expand Up @@ -73,23 73,37 @@ export default class Router {
// on handle pop state (we are moving in history)
// just match route and call change success because we are assuming that everything has been already resolved
// so just change route
const path = location.pathname;
const query = parseQuery(location.search);

resolveWithFirstMatched(this.routes, location.pathname, parseQuery(location.search)).then(
resolveWithFirstMatched(this.routes, path, query).then(
(newRoute) => {
this._currentRoute = newRoute;
const currentRoute = this._currentRoute;

// replace state with new route if is not set (initial load)
if (!location.state) {
this.history.replaceState(
newRoute,
createHref(location.pathname, parseQuery(location.search))
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(
(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;

this._callEventListeners('changeSuccess', newRoute);
this._callEventListeners('changeSuccess', newRoute);

// do nothing about state because it is already store
this.onTransition(null, newRoute);
// do nothing about state because it is already store
this.onTransition(null, newRoute);
}
},
() => {
const e = new RouteNotFoundError('Route not found');
Expand Down Expand Up @@ -133,6 147,36 @@ export default class Router {
};
}

_rejectTransition(reason) {
const err = new Error(reason);

return (parentErr) => {
const e = parentErr || err;
this._callEventListeners('changeFail', e, this._currentRoute, this);
this.onTransition(e);

throw err;
};
}

_finishRun(resolvedRoute, path, query, replace = false) {
this._currentRoute = resolvedRoute;
this._callEventListeners('changeSuccess', resolvedRoute);

if (replace) {
this.history.replaceState(
resolvedRoute,
createHref(path, query)
);
} else {
this.history.pushState(resolvedRoute, createHref(path, query));
}

this.onTransition(null, resolvedRoute);

return resolvedRoute;
}

addChangeStartListener(listener) {
return this._registerEventListener('changeStart', listener);
}
Expand Down Expand Up @@ -175,57 219,6 @@ export default class Router {
* @returns {Promise}
*/
run(path, query = {}) {
const rejectTransition = (reason) => {
const err = new Error(reason);

return (parentErr) => {
const e = parentErr || err;
this._callEventListeners('changeFail', e, this._currentRoute, this);
this.onTransition(e);

throw err;
};
};

const resolveComponents = (components) => {
if (!Array.isArray(components)) {
return Promise.resolve([]);
}

// go through components and if function, call it
return Promise.all(
components.map((component) => {
if (typeof component === 'function') {
try {
// if is react class, it throws error
const result = component();

if (typeof result.then === 'function') {
return result;
}

return component;
} catch (e) {
return component;
}
}

return component;
})
);
};

const finishRun = (resolvedRoute) => {
this._currentRoute = resolvedRoute;
this._callEventListeners('changeSuccess', resolvedRoute);

this.history.pushState(resolvedRoute, createHref(path, query));

this.onTransition(null, resolvedRoute);

return resolvedRoute;
};

const runResolvedRoute = (resolvedRoute) => {
const currentRoute = this._currentRoute;
this._callEventListeners('changeStart', currentRoute, resolvedRoute, this);
Expand All @@ -237,13 230,13 @@ export default class Router {
() => runRouteHandlers('onEnter', resolvedRoute, handlerWrappers, currentRoute, resolvedRoute, this).then(
() => resolveComponents(resolvedRoute.components).then(
(components) => {
return finishRun({ ...resolvedRoute, components });
return this._finishRun({ ...resolvedRoute, components }, path, query);
},
rejectTransition('Route components cannot be resolved')
this._rejectTransition('Route components cannot be resolved')
),
rejectTransition('Route onEnter handlers are rejected.')
this._rejectTransition('Route onEnter handlers are rejected.')
),
rejectTransition('Current route onLeave handlers are rejected.')
this._rejectTransition('Current route onLeave handlers are rejected.')
);
};

Expand Down
28 changes: 28 additions & 0 deletions src/utils/routeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 178,31 @@ export function runRouteHandlers(handlers, route, wrappers = [], ...args) {
);
}
/* eslint-enable consistent-return */

export function resolveComponents(components) {
if (!Array.isArray(components)) {
return Promise.resolve([]);
}

// go through components and if function, call it
return Promise.all(
components.map((component) => {
if (typeof component === 'function') {
try {
// if is react class, it throws error
const result = component();

if (typeof result.then === 'function') {
return result;
}

return component;
} catch (e) {
return component;
}
}

return component;
})
);
}
2 changes: 1 addition & 1 deletion test/Router.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 51,7 @@ describe('Router', () => {
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(false);
expect(changeStart.called).to.be.equal(true);
expect(changeSuccess.calledOnce).to.be.equal(true);

done();
Expand Down

0 comments on commit 85ef5d0

Please sign in to comment.