Skip to content

Support additional state that is not in the URL #828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions modules/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ var Navigation = {
* Transitions to the URL specified in the arguments by pushing
* a new URL onto the history stack.
*/
transitionTo(to, params, query) {
this.context.router.transitionTo(to, params, query);
transitionTo(to, params, query, data) {
this.context.router.transitionTo(to, params, query, data);
},

/**
* Transitions to the URL specified in the arguments by replacing
* the current URL in the history stack.
*/
replaceWith(to, params, query) {
this.context.router.replaceWith(to, params, query);
replaceWith(to, params, query, data) {
this.context.router.replaceWith(to, params, query, data);
},

/**
Expand Down
3 changes: 2 additions & 1 deletion modules/Redirect.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/**
* Encapsulates a redirect to the given route.
*/
function Redirect(to, params, query) {
function Redirect(to, params, query, data) {
this.to = to;
this.params = params;
this.query = query;
this.data = data;
}

module.exports = Redirect;
6 changes: 3 additions & 3 deletions modules/TestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ exports.Async = React.createClass({
statics: {
delay: 10,

willTransitionTo: function (transition, params, query, callback) {
willTransitionTo: function (transition, params, query, callback, data) {
setTimeout(callback, exports.Async.delay);
}
},
Expand All @@ -61,7 +61,7 @@ exports.RedirectToFooAsync = React.createClass({
statics: {
delay: 10,

willTransitionTo: function (transition, params, query, callback) {
willTransitionTo: function (transition, params, query, callback, data) {
setTimeout(function () {
transition.redirect('/foo');
callback();
Expand Down Expand Up @@ -91,7 +91,7 @@ exports.AbortAsync = React.createClass({
statics: {
delay: 10,

willTransitionTo: function (transition, params, query, callback) {
willTransitionTo: function (transition, params, query, callback, data) {
setTimeout(function () {
transition.abort();
callback();
Expand Down
8 changes: 4 additions & 4 deletions modules/Transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Transition.prototype.abort = function (reason) {
this.abortReason = reason || 'ABORT';
};

Transition.prototype.redirect = function (to, params, query) {
this.abort(new Redirect(to, params, query));
Transition.prototype.redirect = function (to, params, query, data) {
this.abort(new Redirect(to, params, query, data));
};

Transition.prototype.cancel = function () {
Expand Down Expand Up @@ -51,14 +51,14 @@ Transition.from = function (transition, routes, components, callback) {
}, callback)();
};

Transition.to = function (transition, routes, params, query, callback) {
Transition.to = function (transition, routes, params, query, data, callback) {
routes.reduceRight(function (callback, route) {
return function (error) {
if (error || transition.abortReason) {
callback(error);
} else if (route.onEnter) {
try {
route.onEnter(transition, params, query, callback);
route.onEnter(transition, params, query, callback, data);

// If there is no callback in the argument list, call it automatically.
if (route.onEnter.length < 4)
Expand Down
4 changes: 2 additions & 2 deletions modules/__tests__/Router-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ describe('Router', function () {
statics: {
delay: Async.delay * 2,

willTransitionTo: function (transition, params, query, callback) {
willTransitionTo: function (transition, params, query, callback, data) {
setTimeout(callback, LongAsync.delay);
}
},
Expand Down Expand Up @@ -585,7 +585,7 @@ describe('Router', function () {
it('ignores aborting asynchronously in willTransitionTo when aborted before router.transitionTo', function (done) {
var AbortAsync2 = React.createClass({
statics: {
willTransitionTo: function (transition, params, query, callback) {
willTransitionTo: function (transition, params, query, callback, data) {
transition.abort();
setTimeout(callback, Async.delay);
}
Expand Down
32 changes: 17 additions & 15 deletions modules/createRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function queryIsActive(activeQuery, query) {
*
* - routes (required) The route config
* - location The location to use. Defaults to HashLocation when
* the DOM is available, "/" otherwise
* the DOM is available, a StaticLocation for "/" otherwise
* - scrollBehavior The scroll behavior to use. Defaults to ImitateBrowserBehavior
* when the DOM is available, null otherwise
* - onError A function that is used to handle errors
Expand Down Expand Up @@ -244,23 +244,23 @@ function createRouter(options) {
* Transitions to the URL specified in the arguments by pushing
* a new URL onto the history stack.
*/
transitionTo: function (to, params, query) {
transitionTo: function (to, params, query, data) {
var path = Router.makePath(to, params, query);

if (pendingTransition) {
// Replace so pending location does not stay in history.
location.replace(path);
location.replace(path, data);
} else {
location.push(path);
location.push(path, data);
}
},

/**
* Transitions to the URL specified in the arguments by replacing
* the current URL in the history stack.
*/
replaceWith: function (to, params, query) {
location.replace(Router.makePath(to, params, query));
replaceWith: function (to, params, query, data) {
location.replace(Router.makePath(to, params, query), data);
},

/**
Expand Down Expand Up @@ -292,7 +292,7 @@ function createRouter(options) {
if (abortReason instanceof Cancellation) {
return;
} else if (abortReason instanceof Redirect) {
location.replace(Router.makePath(abortReason.to, abortReason.params, abortReason.query));
location.replace(Router.makePath(abortReason.to, abortReason.params, abortReason.query), abortReason.data);
} else {
location.pop();
}
Expand All @@ -304,7 +304,7 @@ function createRouter(options) {
},

handleLocationChange: function (change) {
Router.dispatch(change.path, change.type);
Router.dispatch(change.path, change.type, change.data);
},

/**
Expand All @@ -323,13 +323,13 @@ function createRouter(options) {
* transition. To resolve asynchronously, they may use the callback argument. If no
* hooks wait, the transition is fully synchronous.
*/
dispatch: function (path, action) {
dispatch: function (path, action, data) {
Router.cancelPendingTransition();

var prevPath = state.path;
var isRefreshing = action == null;

if (prevPath === path && !isRefreshing)
var hasData = data != null;
if (prevPath === path && !isRefreshing && !hasData)
return; // Nothing to do!

// Record the scroll position as early as possible to
Expand All @@ -355,9 +355,10 @@ function createRouter(options) {
var nextRoutes = match.routes || [];
var nextParams = match.params || {};
var nextQuery = match.query || {};
var nextData = data || {};

var fromRoutes, toRoutes;
if (prevRoutes.length) {
if (data == null && prevRoutes.length) {
fromRoutes = prevRoutes.filter(function (route) {
return !hasMatch(nextRoutes, route, prevParams, nextParams, prevQuery, nextQuery);
});
Expand All @@ -379,14 +380,15 @@ function createRouter(options) {
if (error || transition.abortReason)
return dispatchHandler.call(Router, error, transition); // No need to continue.

Transition.to(transition, toRoutes, nextParams, nextQuery, function (error) {
Transition.to(transition, toRoutes, nextParams, nextQuery, nextData, function (error) {
dispatchHandler.call(Router, error, transition, {
path: path,
action: action,
pathname: match.pathname,
routes: nextRoutes,
params: nextParams,
query: nextQuery
query: nextQuery,
data: nextData
});
});
});
Expand Down Expand Up @@ -433,7 +435,7 @@ function createRouter(options) {
},

refresh: function () {
Router.dispatch(location.getCurrentPath(), null);
Router.dispatch(location.getCurrentPath(), null, location.data);
},

stop: function () {
Expand Down
14 changes: 9 additions & 5 deletions modules/locations/HashLocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ var History = require('../History');
var _listeners = [];
var _isListening = false;
var _actionType;
var _data = [];

function notifyChange(type) {
function notifyChange(type, data) {
if (type === LocationActions.PUSH)
History.length += 1;

var change = {
path: HashLocation.getCurrentPath(),
type: type
type: type,
data: data
};

_listeners.forEach(function (listener) {
Expand All @@ -38,7 +40,7 @@ function onHashChange() {
// manipulation. So just guess 'pop'.
var curActionType = _actionType;
_actionType = null;
notifyChange(curActionType || LocationActions.POP);
notifyChange(curActionType || LocationActions.POP, _data.pop());
}
}

Expand Down Expand Up @@ -80,13 +82,15 @@ var HashLocation = {
}
},

push(path) {
push(path, data) {
_actionType = LocationActions.PUSH;
_data.push(data);
window.location.hash = path;
},

replace(path) {
replace(path, data) {
_actionType = LocationActions.REPLACE;
_data.push(data);
window.location.replace(
window.location.pathname + window.location.search + '#' + path
);
Expand Down
13 changes: 7 additions & 6 deletions modules/locations/HistoryLocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ var History = require('../History');
var _listeners = [];
var _isListening = false;

function notifyChange(type) {
function notifyChange(type, data) {
var change = {
path: HistoryLocation.getCurrentPath(),
type: type
type: type,
data: data
};

_listeners.forEach(function (listener) {
Expand Down Expand Up @@ -57,15 +58,15 @@ var HistoryLocation = {
}
},

push(path) {
push(path, data) {
window.history.pushState({ path: path }, '', path);
History.length += 1;
notifyChange(LocationActions.PUSH);
notifyChange(LocationActions.PUSH, data);
},

replace(path) {
replace(path, data) {
window.history.replaceState({ path: path }, '', path);
notifyChange(LocationActions.REPLACE);
notifyChange(LocationActions.REPLACE, data);
},

pop: History.back,
Expand Down
5 changes: 3 additions & 2 deletions modules/locations/StaticLocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ function throwCannotModify() {
*/
class StaticLocation {

constructor(path) {
this.path = path;
constructor(path, data) {
this.path = path
this.data = data;
}

getCurrentPath() {
Expand Down
8 changes: 4 additions & 4 deletions modules/locations/TestLocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ class TestLocation {
});
}

push(path) {
push(path, data) {
this.history.push(path);
this._updateHistoryLength();
this._notifyChange(LocationActions.PUSH);
this._notifyChange(LocationActions.PUSH, data);
}

replace(path) {
replace(path, data) {
invariant(
this.history.length,
'You cannot replace the current path with no history'
);

this.history[this.history.length - 1] = path;

this._notifyChange(LocationActions.REPLACE);
this._notifyChange(LocationActions.REPLACE, data);
}

pop() {
Expand Down