单击 Safari 上的后退按钮时使用 React 挂钩强制页面重新加载

Posted

技术标签:

【中文标题】单击 Safari 上的后退按钮时使用 React 挂钩强制页面重新加载【英文标题】:Forcing a page reload using React hooks when clicking back button on Safari 【发布时间】:2021-06-25 15:19:33 【问题描述】:

我想强制重新加载页面(即使在使用后退按钮导航时),因为在 Safari 浏览器中,Safari 会加载页面的缓存版本,这不是我们想要的。

使用 React Hooks,我可以在 useEffect 中做到这一点。

function MyComponent() 
    useEffect(() => 
        if (typeof window != 'undefined') 
            window.onpageshow = event => 
                if (event.persisted) 
                    window.location.reload()
                
            
        
    , [])

    return (<div>My Page Content</div>)

我的问题是:这样做时,是否会重复调用重新加载,因为重新加载会触发组件的重新渲染和重新安装,这反过来会调用 useEffect,然后调用 reload 然后进入这个无限循环?

另一种方法是模仿 React 类 constructor

function MyComponent() 
    const [reloadHasRun, setReloadHasRun] = useState(false)

    const forceReload = () => 
        if (typeof window !== 'undefined') 
            window.onpageshow = event => 
                if (event.persisted) 
                    window.location.reload()
                
            
        

        setReloadHasRun(true)
    

    if (!reloadHasRun)
        forceReload()

    return (<div>My Page Content</div>)

但是,我也有同样的问题。强制重新加载是否让我陷入组件不断重新渲染、重新安装以及一遍又一遍调用重新加载的情况?

最终,我希望在 Safari 上单击后退按钮时重新加载前一页,而不仅仅是从缓存中提取。

【问题讨论】:

这能回答你的问题吗? How can I force a component to re-render with hooks in React? 【参考方案1】:

是的,在这两种情况下,如果组件在启动时呈现,我希望页面进入重新加载页面的无限循环。

React 钩子没有任何类型的持久性:它们对您创建的组件实例是有状态的,并且在组件卸载(或页面卸载)时被完全删除

作为建议,我认为您不需要在 React 组件中执行此操作...它只是您想要不时运行的脚本。

这个脚本的实现可以是任何你想要的,但我想到了两个例子:

if(!window.localStorage.getItem('is-refresh')) 
  window.onpageshow = event => 
    if (event.persisted) 
      window.localStorage.setItem('is-refresh', true);
      window.location.reload();
    
  
 else 
  window.localStorage.removeItem('is-refresh');

这将始终只刷新一次页面。或者您可以使用时间戳

const lastUpdate = window.localStorage.getItem('lastUpdate')
const lastUpdateTs = lastUpdate ? Number(lastUpdate) : 0;

if(Date.now() > lastUpdateTs + 3600) 
  window.onpageshow = event => 
    if (event.persisted) 
      window.localStorage.set('lastUpdate', Date.now());
      window.location.reload();
    
  

(当然你也可以把它放在 useEffect 中……但是你有什么理由要等待 React 完成渲染再重新加载?)

【讨论】:

以上是关于单击 Safari 上的后退按钮时使用 React 挂钩强制页面重新加载的主要内容,如果未能解决你的问题,请参考以下文章

单击后退按钮时,React-router 滚动到顶部

单击链接时React Router V5不渲染路由,但后退和前进按钮有效?

当我单击 react-native-video 播放器中的硬件后退按钮时如何锁定 LandScape 模式?

在执行功能时单击导航控制器上的后退按钮时应用程序崩溃

如何禁用 Android 上的设备后退按钮(react-native)?

为啥当我单击基于导航的应用程序上的后退按钮时未调用 viewdidunload 函数