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;