From a5b0094677b8f10e3104cb55c6a21da308ec6534 Mon Sep 17 00:00:00 2001 From: kaykdm <34934746+kaykdm@users.noreply.github.com> Date: Sat, 23 Jan 2021 03:03:29 +0900 Subject: [PATCH] Fix shallow routing scroll (#21437) This ensures that Next.js will not scroll to the top of the page in shallow routing. Fixes: https://github.com/vercel/next.js/issues/21386 Fixes: https://github.com/vercel/next.js/issues/21366 --- .../next/next-server/lib/router/router.ts | 5 ++- .../pages/nav/shallow-routing.js | 21 ++++++++++- .../client-navigation/test/index.test.js | 35 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index c5f464b15f0..6238e1c139a 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -1093,13 +1093,16 @@ export default class Router implements BaseRouter { !(routeInfo.Component as any).getInitialProps } + // shallow routing is only allowed for same page URL changes. + const isValidShallowRoute = options.shallow && this.route === route await this.set( route, pathname!, query, cleanedAs, routeInfo, - forcedScroll || (options.scroll ? { x: 0, y: 0 } : null) + forcedScroll || + (isValidShallowRoute || !options.scroll ? null : { x: 0, y: 0 }) ).catch((e) => { if (e.cancelled) error = error || e else throw e diff --git a/test/integration/client-navigation/pages/nav/shallow-routing.js b/test/integration/client-navigation/pages/nav/shallow-routing.js index 61dc8032249..728467f9afd 100644 --- a/test/integration/client-navigation/pages/nav/shallow-routing.js +++ b/test/integration/client-navigation/pages/nav/shallow-routing.js @@ -27,6 +27,17 @@ export default class extends Component { Router.push(href, href, { shallow: true }) } + increaseNonShallow() { + const counter = this.getCurrentCounter() + const href = `/nav/shallow-routing?counter=${counter + 1}` + Router.push(href, href, {}) + } + + gotoNavShallow() { + const href = `/nav` + Router.push(href, href, { shallow: true }) + } + render() { return (
@@ -35,13 +46,21 @@ export default class extends Component { Home -
Counter: {this.getCurrentCounter()}
+
+ Counter: {this.getCurrentCounter()} +
getInitialProps run count: {this.props.getInitialPropsRunCount}
+ +
) } diff --git a/test/integration/client-navigation/test/index.test.js b/test/integration/client-navigation/test/index.test.js index d6c00e0bbfd..0d87cdeda14 100644 --- a/test/integration/client-navigation/test/index.test.js +++ b/test/integration/client-navigation/test/index.test.js @@ -854,6 +854,41 @@ describe('Client Navigation', () => { await browser.close() }) + + it('should keep the scroll position on shallow routing', async () => { + const browser = await webdriver(context.appPort, '/nav/shallow-routing') + await browser.eval(() => + document.querySelector('#increase').scrollIntoView() + ) + const scrollPosition = await browser.eval('window.pageYOffset') + + expect(scrollPosition).toBeGreaterThan(3000) + + await browser.elementByCss('#increase').click() + await waitFor(500) + const newScrollPosition = await browser.eval('window.pageYOffset') + + expect(newScrollPosition).toBe(scrollPosition) + + await browser.elementByCss('#increase2').click() + await waitFor(500) + const newScrollPosition2 = await browser.eval('window.pageYOffset') + + expect(newScrollPosition2).toBe(0) + + await browser.eval(() => + document.querySelector('#invalidShallow').scrollIntoView() + ) + const scrollPositionDown = await browser.eval('window.pageYOffset') + + expect(scrollPositionDown).toBeGreaterThan(3000) + + await browser.elementByCss('#invalidShallow').click() + await waitFor(500) + const newScrollPosition3 = await browser.eval('window.pageYOffset') + + expect(newScrollPosition3).toBe(0) + }) }) describe('with URL objects', () => {