在浏览器中按下后退/前进按钮时,有没有办法在重新渲染之前改变行为

Posted

技术标签:

【中文标题】在浏览器中按下后退/前进按钮时,有没有办法在重新渲染之前改变行为【英文标题】:Is there a way to change behaviour before rerender when back/forward buttons pressed in browser 【发布时间】:2022-01-23 06:10:51 【问题描述】:

大家好,希望你们一切都好,为圣诞节做好准备

所以我有这个功能组件,当您按下链接更改页面时,它会播放动画。这确实不错,但在 ios 版 Safari 等浏览器上完全存在问题,因为您可以来回滑动手势。

我需要一个组件能够检查重新渲染是否由后退/前进按钮按下/手势引起,然后更改变量以停止动画等。

这是组件,所有不重要的东西都被明显删除了。

此组件已删除所有后退按钮/前进按钮检测代码的尝试。

我们希望引用 noTransition.current 在 URL 因按下这些按钮而发生变化时发生变化。此值必须在按下按钮后发生任何重新呈现之前更改。

const Central = (props) => 
    let location = useLocation();

    var noTransition = useRef(true);
    const history = useNavigate()

    noTransition.current = false;

    return (
        <div className="centralMain">
            <SlickContainer noTransition=noTransition.current/>
            /* actual component here doesn't matter, just the fact that the "noTransition" attribute must change */
        </div>
    )


export default Central

我已经测试了大约 10 亿个解决方案,有些很有希望,但都非常老套。我对拥有一个 window.onpopstate 监听器的想法感到非常兴奋,它会改变 noTransition.current 的值,但我很快(几个小时后)了解到,当 URL 更改时的渲染实际上发生在监听器触发之前,所以它是徒劳的.

我也尝试过将useEffects 用于导航器之类的东西,但后来我了解到useEffect 在渲染后实际上会触发...

我还尝试了一些非常古怪的想法,通过状态从链接传递时间值并比较它已经持续了多长时间。这最终是一个 hack,我需要一个适当的解决方案。

如果您有任何想法,或需要任何其他信息或代码,请告诉我。

请注意,我们很遗憾使用的是 react-router v6。

感谢您的收听,请帮助我。

【问题讨论】:

您是否尝试过任何有希望的方法,但使用useLayoutEffect 而不是useEffect?嗅探用户代理并在特定 iOS 版本上禁用动画怎么样? @DrewReese 我将尝试 useLayoutEffect,我曾考虑在 iOS 上禁用动画,但这是一个相当大的举措,因为大多数在手机上看过早期版本的人都表示页面之间的动画看起来很酷。谢谢,我试试useLayoutEffect后会更新 哦,你是在使用 between 路由的过渡,而不是在新路由组件挂载时使用一些动画吗?我不确定路由转换在 RRDv6 中是否有效……至少不像在 v5 中那样。可能需要检查文档。 【参考方案1】:

您可以使用自定义history 来监听导航事件。

// history.js

import history from 'history/browser'; // v6
// import  createBrowserHistory  from 'history'; // v5
// const history = createBrowserHistory(); // v5

export default history;


// app.js

import  CustomRouter  from './customRouter';
import history from './history';

const App = () => 

  ...
  /* Use Router instead of BrowserRouter and add custom-history */
  <CustomRouter navigator=history> /* prop is called history for v5 */
    ... routes
  </CustomRouter>

  ...

...

// component

const Central = (props) => 
    const noTransition = useRef(false);

    useEffect(() => 
        const unlisten = history.listen(( action, location ) => 
            // POP === popstate event; browser back/forward navigation
            noTransition.current = action === 'POP' ? false : true;
        );
        return unlisten;
    , []);

    return (
        <div className="centralMain">
            /* Pass ref instead of value and access ref.current inside container */
            <SlickContainer noTransition=noTransition.current/>
            /* actual component here doesn't matter, just the fact that the "noTransition" attribute must change */
        </div>
    )


export default Central

请参阅this 答案以了解基本的 CustomRouter 实现!

【讨论】:

OP 使用的是react-router-dom v6,它不会轻易暴露history 对象。 确实如此,我会更新我的答案 当然,您可以创建自定义路由器实例,但location 也是必需的道具。有关基本实现,请参阅我的答案之一 here。 感谢您的回答。它看起来确实很有希望,但是 location.state = action === 'POP' ? false : true; 行让程序非常不安:“TypeError: Cannot assign to read only property 'state' of object '#&lt;Object&gt;' 我不知道位置状态是只读的。您基本上只是想确定是否应禁用转换 - 并将此信息传递给组件。将更新答案

以上是关于在浏览器中按下后退/前进按钮时,有没有办法在重新渲染之前改变行为的主要内容,如果未能解决你的问题,请参考以下文章

在颤动中按下移动后退按钮后网站应用程序未退出

为啥在laravel中按下浏览器的后退按钮时过滤器不起作用?

当用户再次导航返回和前进时强制刷新/重新加载

在iOS中按下后退按钮时如何创建确认弹出窗口?

连续按下按钮时如何加快前进/后退过程

在父活动上按下后退按钮