diff --git a/modules/__tests__/Router-test.js b/modules/__tests__/Router-test.js
index 7b9bad4b5e..730d30008a 100644
--- a/modules/__tests__/Router-test.js
+++ b/modules/__tests__/Router-test.js
@@ -2,6 +2,7 @@ var expect = require('expect');
var React = require('react');
var Router = require('../index');
var Route = require('../components/Route');
+var RouteHandler = require('../components/RouteHandler');
var TestLocation = require('../locations/TestLocation');
var ScrollToTopBehavior = require('../behaviors/ScrollToTopBehavior');
var getWindowScrollPosition = require('../utils/getWindowScrollPosition');
@@ -533,8 +534,22 @@ describe('Router', function () {
});
});
- it('execute willTransition* callbacks when query changes', function (done) {
- var fromCallbackExecuted = false;
+ it('executes transition hooks when only the query changes', function (done) {
+ var fromKnifeCalled = false;
+ var fromSpoonCalled = false;
+
+ var Knife = React.createClass({
+ statics: {
+ willTransitionFrom: function () {
+ fromKnifeCalled = true;
+ }
+ },
+
+ render: function () {
+ return ;
+ }
+ });
+
var Spoon = React.createClass({
statics: {
willTransitionTo: function (transition, params, query) {
@@ -543,12 +558,13 @@ describe('Router', function () {
}
expect(query['filter']).toEqual('second');
- expect(fromCallbackExecuted).toBe(true);
+ expect(fromKnifeCalled).toBe(true);
+ expect(fromSpoonCalled).toBe(true);
done();
},
willTransitionFrom: function (transition, element) {
- fromCallbackExecuted = true;
+ fromSpoonCalled = true;
}
},
@@ -558,7 +574,7 @@ describe('Router', function () {
});
var routes = (
-
+
);
diff --git a/modules/utils/createRouter.js b/modules/utils/createRouter.js
index 42abb9dab6..2109d21fa6 100644
--- a/modules/utils/createRouter.js
+++ b/modules/utils/createRouter.js
@@ -91,7 +91,15 @@ function createMatch(route, params) {
return { routes: [ route ], params: params };
}
-function hasMatch(routes, route, prevParams, nextParams) {
+function hasProperties(object, properties) {
+ for (var propertyName in properties)
+ if (properties.hasOwnProperty(propertyName) && object[propertyName] !== properties[propertyName])
+ return false;
+
+ return true;
+}
+
+function hasMatch(routes, route, prevParams, nextParams, prevQuery, nextQuery) {
return routes.some(function (r) {
if (r !== route)
return false;
@@ -99,6 +107,7 @@ function hasMatch(routes, route, prevParams, nextParams) {
var paramNames = route.paramNames;
var paramName;
+ // Ensure that all params the route cares about did not change.
for (var i = 0, len = paramNames.length; i < len; ++i) {
paramName = paramNames[i];
@@ -106,7 +115,8 @@ function hasMatch(routes, route, prevParams, nextParams) {
return false;
}
- return true;
+ // Ensure the query hasn't changed.
+ return hasProperties(prevQuery, nextQuery) && hasProperties(nextQuery, prevQuery);
});
}
@@ -335,6 +345,7 @@ function createRouter(options) {
var prevRoutes = state.routes || [];
var prevParams = state.params || {};
+ var prevQuery = state.query || {};
var nextRoutes = match.routes || [];
var nextParams = match.params || {};
@@ -343,27 +354,17 @@ function createRouter(options) {
var fromRoutes, toRoutes;
if (prevRoutes.length) {
fromRoutes = prevRoutes.filter(function (route) {
- return !hasMatch(nextRoutes, route, prevParams, nextParams);
+ return !hasMatch(nextRoutes, route, prevParams, nextParams, prevQuery, nextQuery);
});
toRoutes = nextRoutes.filter(function (route) {
- return !hasMatch(prevRoutes, route, prevParams, nextParams);
+ return !hasMatch(prevRoutes, route, prevParams, nextParams, prevQuery, nextQuery);
});
} else {
fromRoutes = [];
toRoutes = nextRoutes;
}
- // If routes' hooks arrays are empty, then we transition to current route.
- // But path is somehow still get changed.
- // That could be only because of route query changes.
- // Need to push current route to routes' hooks arrays.
- if (!toRoutes.length && !fromRoutes.length) {
- var currentRoute = state.routes[state.routes.length-1];
- fromRoutes = [currentRoute];
- toRoutes = [currentRoute];
- }
-
var transition = new Transition(path, this.replaceWith.bind(this, path));
pendingTransition = transition;