Safari浏览器使用react-router-dom点击前进后退时状态持久化不更新问题
Safari环境react-router-dom前进后退状态不重置解决方案
问题根因
该问题是Safari特有的往返缓存(bfcache)机制和旧版react-router-dom路由监听逻辑不兼容导致的:
- Safari的bfcache会在用户触发前进后退、滑动返回操作时,直接加载页面内存快照,不会触发常规的页面加载事件
- 你当前使用的是react-router-dom v5版本(通过Switch标签判定为v5),部分旧版本的路由监听无法被bfcache恢复的页面触发,导致URL更新但路由状态没有同步,组件不会重渲,旧状态残留
方案1:全局适配bfcache事件,无刷新同步路由状态
该方案不需要修改业务代码,也不会触发全页刷新,只会触发react-router内部的路由重匹配,性能损耗极低:
在你的App组件中添加pageshow事件监听,检测到从bfcache恢复时主动触发路由同步,代码如下:
import { useHistory } from 'react-router-dom' import { useEffect } from 'react' export default function App() { const history = useHistory() useEffect(() => { const handlePageShow = (event) => { // 判定当前页面是从bfcache恢复的 if (event.persisted) { // 用当前路径执行replace操作,触发路由重匹配,不会刷新页面 history.replace(history.location) } } window.addEventListener('pageshow', handlePageShow) return () => window.removeEventListener('pageshow', handlePageShow) }, [history]) // 保留原有App组件的其余代码不变 }
方案2:路由组件绑定动态key,强制路由变化时重建组件
如果方案1无法覆盖所有场景(比如部分组件状态完全和路由解绑的情况),可以通过给路由组件绑定和路由关联的key,只要路由变化组件就会自动卸载重建,旧状态完全清除:
修改你的RouteWithSubRoutes组件逻辑即可:
const RouteWithSubRoutes = (route) => { return ( <Route exact={route.exact || undefined} path={route.path} render={(props) => ( // key绑定路由的唯一标识,路由变化时组件强制重建,自动清空内部状态 <route.component {...props} key={props.location.key} /> )} /> ); }
首页的路由也可以同步调整,加上key属性:
<Route exact path="/" render={props => <Home {...props} key={props.location.key} />} />
方案3:升级react-router-dom版本
当前你使用的v5版本已经停止维护,升级到v5最新稳定版或者v6版本,官方已经原生适配了Safari bfcache的路由同步逻辑,不需要额外做兼容处理。
内容的提问来源于stack exchange,提问作者YaBCK
相关产品推荐
相关产品推荐

