Skip to content

Commit 5fe6c08

Browse files
committed
[changed] Don't update scroll if only query has changed
Previously, the only way to opt out of scroll updates for a route would be by using `ignoreScrollBehavior`. This, however, made it hard to implement arguably the most common use case: resetting scroll when `params` change and preserving it when only `query` changes. This commit completely disables scroll updates when only `query` has changed. This provides a reasonable default behavior and leaves `ignoreScrollBehavior` for more complicated cases. If you'd rather keep the old behavior and reset scroll on query changes, you can either promote `query` variables to be route `params` or reset scroll position yourself in response to `query` changes in route handler's `componentDidUpdate`. Fixes #432, #439
1 parent 0dce2e9 commit 5fe6c08

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

modules/__tests__/Router-test.js

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ describe('Router.run', function () {
353353
<Route handler={Foo} path='/feed' />
354354
<Route handler={Foo} path='/discover' />
355355
</Route>
356-
<Route path='/search' handler={Foo} ignoreScrollBehavior />
356+
<Route path='/search/:q' handler={Foo} ignoreScrollBehavior />
357+
<Route path='/users/:id/posts' handler={Foo} />
357358
<Route path='/about' handler={Foo} />
358359
</Route>
359360
);
@@ -406,25 +407,50 @@ describe('Router.run', function () {
406407
});
407408

408409
it('calls updateScroll when no ancestors ignore scroll although source and target do', function () {
409-
TestLocation.push('/search');
410+
TestLocation.push('/search/foo');
410411
expect(didUpdateScroll).toBe(true);
411412
});
412413

413-
it('calls updateScroll when source is same as target and does not ignore scroll', function () {
414-
TestLocation.push('/about?page=2');
414+
it('calls updateScroll when route does not ignore scroll and only params change', function () {
415+
TestLocation.replace('/users/3/posts');
416+
didUpdateScroll = false;
417+
418+
TestLocation.push('/users/5/posts');
419+
expect(didUpdateScroll).toBe(true);
420+
});
421+
422+
it('calls updateScroll when route does not ignore scroll and both params and query change', function () {
423+
TestLocation.replace('/users/3/posts');
424+
didUpdateScroll = false;
425+
426+
TestLocation.push('/users/5/posts?page=2');
415427
expect(didUpdateScroll).toBe(true);
416428
});
417429

430+
it('does not call updateScroll when route does not ignore scroll but only query changes', function () {
431+
TestLocation.replace('/users/3/posts');
432+
didUpdateScroll = false;
433+
434+
TestLocation.push('/users/3/posts?page=2');
435+
expect(didUpdateScroll).toBe(false);
436+
});
437+
418438
it('does not call updateScroll when common ancestor ignores scroll', function () {
419439
TestLocation.push('/discover');
420440
expect(didUpdateScroll).toBe(false);
421441
});
422442

423-
it('does not call updateScroll when source is same as target and ignores scroll', function () {
424-
TestLocation.push('/search');
443+
it('does not call updateScroll when route ignores scroll', function () {
444+
TestLocation.replace('/search/foo');
425445
didUpdateScroll = false;
426446

427-
TestLocation.push('/search?q=test');
447+
TestLocation.push('/search/bar');
448+
expect(didUpdateScroll).toBe(false);
449+
450+
TestLocation.replace('/search/bar?safe=0');
451+
expect(didUpdateScroll).toBe(false);
452+
453+
TestLocation.replace('/search/whatever');
428454
expect(didUpdateScroll).toBe(false);
429455
});
430456
});

modules/mixins/Scrolling.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
var invariant = require('react/lib/invariant');
22
var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
33
var getWindowScrollPosition = require('../utils/getWindowScrollPosition');
4+
var Path = require('../utils/Path');
45

56
function shouldUpdateScroll(state, prevState) {
67
if (!prevState) {
78
return true;
89
}
910

11+
var path = state.path;
1012
var routes = state.routes;
13+
var prevPath = prevState.path;
1114
var prevRoutes = prevState.routes;
1215

16+
if (Path.withoutQuery(path) === Path.withoutQuery(prevPath)) {
17+
return false;
18+
}
19+
1320
var sharedAncestorRoutes = routes.filter(function (route) {
1421
return prevRoutes.indexOf(route) !== -1;
1522
});

0 commit comments

Comments
 (0)