最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Next.js behavior on back button pressed - Stack Overflow

programmeradmin12浏览0评论

I have a page I am trying to fix in order to keep scroll position when user presses back button (browser). Let's say I have a ponent called list, where I show the user some products. To see all the products the user can scroll down the list ponent. When the user clicks on some product, the application redirects the user to the detail ponent. Then when the user tries to go back to the list, hits the back button of the browser, the list ponent gets rendered and it seems like it scrolls to top automatically.

As far as I know, pressing the back button of the browser triggers a window.history.back() action, nothing else happens.

For a solution, I have implemented a variable in the context of my application that saves the scrollY value and then, in the ponentWillMount (or useEffect) of the ponent I am trying to render (list ponent), I set the scroll position to the value set in the context.

Details of my solution are here, as I have based my entire code in this stack overflow's post: How to change scroll behavior while going back in next js?

I have checked the value using some logs and the scroll position is saved correctly in the context, however, as I am using a window event listener, it sets the value to zero just after the list ponent is rendered.

In my code I am not using any kind of scroll configuration, so I was wondering if that behavior is some sort of default for either Next.js or react. It happens when the user hits the back button of the browser, but I am a newbie to next and I don't know if I am missing something or what, I don't even know if this issue has something to do with React or Next.js itself.

I have a page I am trying to fix in order to keep scroll position when user presses back button (browser). Let's say I have a ponent called list, where I show the user some products. To see all the products the user can scroll down the list ponent. When the user clicks on some product, the application redirects the user to the detail ponent. Then when the user tries to go back to the list, hits the back button of the browser, the list ponent gets rendered and it seems like it scrolls to top automatically.

As far as I know, pressing the back button of the browser triggers a window.history.back() action, nothing else happens.

For a solution, I have implemented a variable in the context of my application that saves the scrollY value and then, in the ponentWillMount (or useEffect) of the ponent I am trying to render (list ponent), I set the scroll position to the value set in the context.

Details of my solution are here, as I have based my entire code in this stack overflow's post: How to change scroll behavior while going back in next js?

I have checked the value using some logs and the scroll position is saved correctly in the context, however, as I am using a window event listener, it sets the value to zero just after the list ponent is rendered.

In my code I am not using any kind of scroll configuration, so I was wondering if that behavior is some sort of default for either Next.js or react. It happens when the user hits the back button of the browser, but I am a newbie to next and I don't know if I am missing something or what, I don't even know if this issue has something to do with React or Next.js itself.

Share Improve this question edited Sep 6, 2021 at 16:57 juliomalves 50.6k23 gold badges178 silver badges169 bronze badges asked Sep 6, 2021 at 15:32 Henry PeregrinoHenry Peregrino 1361 gold badge2 silver badges8 bronze badges 2
  • dude it also happens to me and I am still figuring out how to fix this one – sairaj Commented Sep 6, 2021 at 15:34
  • I found that in my case Chrome and Firefox behave differently regarding preservation of the (redux) state and calling useEffect hooks when clicking the browsers "history back" button. There are a too many details to put in this ment, but in my case Firefox calls useEffect and resets to the initial state, Chrome doesn't call any hooks and restores the state at the point when the page (the one to which you are returning to) was left. – kca Commented Jan 25, 2023 at 15:02
Add a ment  | 

3 Answers 3

Reset to default 1

This gist may be of assistance as it includes a custom hook to manage scroll position: https://gist.github./claus/992a5596d6532ac91b24abe24e10ae81

import { useEffect } from 'react';

import Router from 'next/router';

function saveScrollPos(url) {
    const scrollPos = { x: window.scrollX, y: window.scrollY };
    sessionStorage.setItem(url, JSON.stringify(scrollPos));
}

function restoreScrollPos(url) {
    const scrollPos = JSON.parse(sessionStorage.getItem(url));
    if (scrollPos) {
        window.scrollTo(scrollPos.x, scrollPos.y);
    }
}

export default function useScrollRestoration(router) {
    useEffect(() => {
        if ('scrollRestoration' in window.history) {
            let shouldScrollRestore = false;
            window.history.scrollRestoration = 'manual';
            restoreScrollPos(router.asPath);

            const onBeforeUnload = event => {
                saveScrollPos(router.asPath);
                delete event['returnValue'];
            };

            const onRouteChangeStart = () => {
                saveScrollPos(router.asPath);
            };

            const onRouteChangeComplete = url => {
                if (shouldScrollRestore) {
                    shouldScrollRestore = false;
                    restoreScrollPos(url);
                }
            };

            window.addEventListener('beforeunload', onBeforeUnload);
            Router.events.on('routeChangeStart', onRouteChangeStart);
            Router.events.on('routeChangeComplete', onRouteChangeComplete);
            Router.beforePopState(() => {
                shouldScrollRestore = true;
                return true;
            });

            return () => {
                window.removeEventListener('beforeunload', onBeforeUnload);
                Router.events.off('routeChangeStart', onRouteChangeStart);
                Router.events.off('routeChangeComplete', onRouteChangeComplete);
                Router.beforePopState(() => true);
            };
        }
    }, [router]);
}

Looking at your url, using shallow routing could solve the problem. Where the URL will get updated. And the page won't get replaced, only the state of the route is changed. So you can change your logic according to that.

A good example is in the official documentation: https://nextjs/docs/routing/shallow-routing

And you might use display: 'hidden' to hide and show your ponents conditionally according to your state!

It's a way around but it could be even more useful depending on your exact situation !

After looking for another solution that does not use the window.scroll and similar methods, I have found a solution.

1st solution (worked, but for me that I have an infinite list that is loaded via API call, sometimes the window.scroll method wasn't accurate): I take the window.scrollY value and set it in the session storage, I did this before leaving the list page, so in the details page, if user hits the back button, at the moment the page is loading, I get the Y value from session storage and use the window.scroll method to force the page to scroll to the previously configured value. As I mentioned earlier, this worked, but in my case, I have a list that is populated from an async API call, so sometimes the page loaded without all the images and the scroll was already configured, then the images and data were loaded and the user ended up seeing some other place in the page rather than the desire position.

2nd solution: In my case we are talking about a e merce app, so I found this solution useful as it focuses in a particular item with its corresponding ID instead of the Y coord of the window. Scroll Restoration in e merce app

发布评论

评论列表(0)

  1. 暂无评论