Next.js在按下回退按钮时的行为

4
我正在尝试修复一个页面,以便在用户按下后退按钮(浏览器)时保持滚动位置。假设我有一个名为“列表”的组件,其中显示了一些产品供用户查看。为了查看所有产品,用户可以向下滚动列表组件。当用户点击某个产品时,应用程序将用户重定向到详细信息组件。然后,当用户尝试返回列表并按下浏览器的后退按钮时,列表组件会被呈现,并且似乎会自动滚动到顶部。
据我所知,按下浏览器的后退按钮会触发window.history.back()操作,仅此而已。
为解决这个问题,我在应用程序的上下文中实现了一个变量来保存scrollY值,然后在我正在尝试渲染的组件(列表组件)的componentWillMount(或useEffect)中,我将滚动位置设置为上下文中设置的值。
我的解决方案的详细信息在此处,因为我已经基于这个stackoverflow帖子编写了整个代码: 如何在下一个js中在返回时更改滚动行为?

我已经通过一些日志检查了值,并且滚动位置在上下文中正确保存,但是由于我正在使用窗口事件监听器,因此它在列表组件呈现后将值设置为零。

在我的代码中,我没有使用任何类型的滚动配置,所以我想知道这种行为是否是Next.js或React的某种默认行为。当用户点击浏览器的后退按钮时会发生这种情况,但我是Next.js的新手,我不知道是否漏掉了什么或者这个问题是否与React或Next.js本身有关。


老兄,这种情况我也遇到过,我还在努力找解决方法。 - sairaj
我发现在我的情况下,Chrome和Firefox在单击浏览器的“历史记录后退”按钮时,在保留(redux)状态和调用useEffect钩子方面表现不同。有太多细节无法在此评论中说明,但在我的情况下,Firefox调用useEffect并重置为初始状态,Chrome不调用任何钩子,并将状态恢复到页面(您要返回的页面)离开时的状态。 - kca
3个回答

1
这个代码片段可能会有所帮助,因为它包含了一个自定义钩子来管理滚动位置:https://gist.github.com/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]);
}

0

看了一下你的 URL,使用浅层路由可能会解决问题。URL 会得到更新,但页面不会被替换,只有路由状态被更改。因此,您可以根据那个来更改你的逻辑。

一个很好的例子是在官方文档中: https://nextjs.org/docs/routing/shallow-routing

而且您可以使用 display: 'hidden' 按照您的状态有条件地隐藏和显示组件!

这是一种解决方法,取决于您确切的情况,它可能会更加有用!


0

在寻找不使用window.scroll和类似方法的另一种解决方案后,我找到了一个解决办法。

第一种解决方案(有效,但对于我来说,由于我的无限列表是通过API调用加载的,有时window.scroll方法不准确):我获取window.scrollY的值并将其设置在会话存储中,在离开列表页面之前,我这样做,所以在详细页面上,如果用户点击返回按钮,在页面加载时,我从会话存储中获取Y值,并使用window.scroll方法强制页面滚动到先前配置的值。 正如我之前提到的,这个方法有效,但在我的情况下,我有一个从异步API调用中填充的列表,所以有时页面加载时并没有加载所有的图片,而滚动已经配置好了,然后图片和数据被加载,用户最终看到的是页面中的其他位置,而不是期望的位置。

第二种解决方案:在我的情况下,我们谈论的是一个电子商务应用程序,所以我发现这个解决方案很有用,因为它专注于特定项目及其相应的ID,而不是窗口的Y坐标。电子商务应用程序中的滚动恢复


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接