UNPKG

react-router

Version:
148 lines (125 loc) 4.26 kB
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } import { loopAsync } from './AsyncUtils'; var PendingHooks = function PendingHooks() { var _this = this; _classCallCheck(this, PendingHooks); this.hooks = []; this.add = function (hook) { return _this.hooks.push(hook); }; this.remove = function (hook) { return _this.hooks = _this.hooks.filter(function (h) { return h !== hook; }); }; this.has = function (hook) { return _this.hooks.indexOf(hook) !== -1; }; this.clear = function () { return _this.hooks = []; }; }; var enterHooks = new PendingHooks(); var changeHooks = new PendingHooks(); function createTransitionHook(hook, route, asyncArity, pendingHooks) { var isSync = hook.length < asyncArity; var transitionHook = function transitionHook() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } hook.apply(route, args); if (isSync) { var callback = args[args.length - 1]; // Assume hook executes synchronously and // automatically call the callback. callback(); } }; pendingHooks.add(transitionHook); return transitionHook; } function getEnterHooks(routes) { return routes.reduce(function (hooks, route) { if (route.onEnter) hooks.push(createTransitionHook(route.onEnter, route, 3, enterHooks)); return hooks; }, []); } function getChangeHooks(routes) { return routes.reduce(function (hooks, route) { if (route.onChange) hooks.push(createTransitionHook(route.onChange, route, 4, changeHooks)); return hooks; }, []); } function runTransitionHooks(length, iter, callback) { if (!length) { callback(); return; } var redirectInfo = void 0; function replace(location) { redirectInfo = location; } loopAsync(length, function (index, next, done) { iter(index, replace, function (error) { if (error || redirectInfo) { done(error, redirectInfo); // No need to continue. } else { next(); } }); }, callback); } /** * Runs all onEnter hooks in the given array of routes in order * with onEnter(nextState, replace, callback) and calls * callback(error, redirectInfo) when finished. The first hook * to use replace short-circuits the loop. * * If a hook needs to run asynchronously, it may use the callback * function. However, doing so will cause the transition to pause, * which could lead to a non-responsive UI if the hook is slow. */ export function runEnterHooks(routes, nextState, callback) { enterHooks.clear(); var hooks = getEnterHooks(routes); return runTransitionHooks(hooks.length, function (index, replace, next) { var wrappedNext = function wrappedNext() { if (enterHooks.has(hooks[index])) { next.apply(undefined, arguments); enterHooks.remove(hooks[index]); } }; hooks[index](nextState, replace, wrappedNext); }, callback); } /** * Runs all onChange hooks in the given array of routes in order * with onChange(prevState, nextState, replace, callback) and calls * callback(error, redirectInfo) when finished. The first hook * to use replace short-circuits the loop. * * If a hook needs to run asynchronously, it may use the callback * function. However, doing so will cause the transition to pause, * which could lead to a non-responsive UI if the hook is slow. */ export function runChangeHooks(routes, state, nextState, callback) { changeHooks.clear(); var hooks = getChangeHooks(routes); return runTransitionHooks(hooks.length, function (index, replace, next) { var wrappedNext = function wrappedNext() { if (changeHooks.has(hooks[index])) { next.apply(undefined, arguments); changeHooks.remove(hooks[index]); } }; hooks[index](state, nextState, replace, wrappedNext); }, callback); } /** * Runs all onLeave hooks in the given array of routes in order. */ export function runLeaveHooks(routes, prevState) { for (var i = 0, len = routes.length; i < len; ++i) { if (routes[i].onLeave) routes[i].onLeave.call(routes[i], prevState); } }