带有参数的Ionic React导航在与浏览器后退按钮结合使用时会完全中断导航

bfrts1fy  于 2023-10-14  发布在  Ionic
关注(0)|答案(2)|浏览(154)

这个问题在@ionic/react 7.4和7.5两个版本中都存在。
我有两个简单的路由定义如下:

<IonRouterOutlet id="main">
...
<Route path="/campaigns" exact={true} render={props => <CampaignList {...props} />} />
<Route path="/campaign/:title" exact={true} render={props => <CampaignDetail {...props} />} />
...
</IonRouterOutlet>

第一个路由显示一个列表,每个列表项都定义了一个onClick方法,该方法调用一个名为getCampaignDetail的方法,该方法导航到第二个路由,如下所示:

const getCampaignDetail = (title:string) => {
  navigate(`/campaign/${title}`, 'root');
}

当我加载应用程序时,它默认为/campaigns
该视图加载没有问题,并显示列表
如果我点击一个列表项,它会正确导航到/campaign/:title

然后使用浏览器的后退按钮加载/campaigns

/campaigns视图加载没有问题

然后,在点击不同的列表项时,我可以说我绝对肯定它试图加载不同的:title,因为:

1.我在控制台记录值之前,它导航,并看到该值显然是不同
1.浏览器中的URL清楚地显示好像参数:title是不同的,并且从我上次访问此路由时起已经更改
尽管如此,当我在CampaignDetail组件中控制台记录:title时(useIonViewDidEnter方法中的/campaign/:title加载的组件),:title正在打印,就好像它的值从我第一次访问/campaign:title没有改变一样。
在我的CampaignDetail组件中,我尝试了两种方法之一检索参数,第一种是直接从props中检索:

type MatchParams = {
  title: string;
};
const CampaignDetail: React.FC<RouteComponentProps> = (props) => {
const { title } = props.match.params as MatchParams;
...

使用useParams钩子:

const CampaignDetail: React.FC<RouteComponentProps> = (props) => {
const { title } = useParams<{ title: string; }>();
...

useIonViewDidEnter方法中,我尝试控制台日志:title

useIonViewDidEnter(() => {
  console.log("PARAMETER:", title);
});

此行为仅在使用浏览器的后退按钮后发生。

为什么在使用浏览器的后退按钮后,参数不能反映后续访问的正确值?

在阅读文档并对此问题进行其他研究后,为了解决此问题,我尝试向路由添加key作为解决方案,如下所示

<Route path="/campaign/:title" exact={true} render={props => <CampaignDetail key={props.match.params.title} {...props} />} />

然而,这会导致甚至更糟糕的行为,因为在使用浏览器的后退按钮之后,对/campaign:title的后续访问会导致useIonViewDidEnter方法执行多次,并且每次执行时,我都会看到:title的行为就像是在我每次打印到控制台时访问的两个值之间切换一样。首先,我看到的值是我第一次访问时的值,然后是新的值,然后它打印第一个值,大约3-4次,最后才停止。
看到这种行为说明了很多问题,因为使用浏览器的后退按钮显然会导致与路由参数有关的奇怪行为。
我能做些什么来解决这个问题?

更新:

我注意到,当我在路由/campaign/:title上点击浏览器的后退按钮时,组件CampaignDetail中的useIonViewDidEnter函数再次触发,而它不应该考虑到我已经离开了该路由并导航回/campaigns

其他异常行为:

根据@Aafaq的建议,我检查location作为故障排除的一种手段,我这样做了,结果发现了奇怪的行为。
如果我将useIonViewDidEnter方法全部注解掉,并使用下面的useEffect钩子和location来检查路径更改,如下所示:

const campaignDetailTitleRef = useRef('');

  useEffect(() => {

    const parts = location.pathname.split('/');
    const getPathTitle = parts[2];

    if (getPathTitle && getPathTitle !== campaignDetailTitleRef.current) {
      campaignDetailTitleRef.current = getPathTitle;
      console.log("PARAMETER:", getPathTitle);
    }
  
  },[location.pathname]);

当应用程序加载启动路由/campaigns,然后我点击一个列表项,我看到console.log("PARAMETER:", getPathTitle);只打印一次,正如预期的那样,当/campaign/:title加载时,它显示正确的值,因为它是从location解析的。

然后我点击浏览器的后退按钮,随后,我点击了一个不同的列表项,虽然getPathTitle的值实际上是正确的打印现在已经从location而不是params检索到该值,我看到console.log("PARAMETER:", getPathTitle);打印两次这告诉我,要么campaignDetailTitleRef.current = getPathTitle在钩子第一次运行后没有设置,要么组件加载了两次,很难判断是哪种情况。很难排除正在发生的故障。

像页面导航这样简单的事情,在url中只需要一个动态参数,应该不会那么困难。这使得Ionic React在浏览器中毫无价值。

wj8zmpe1

wj8zmpe11#

我建议您使用react-router-dom中的useLocation钩子来记录当前位置及其状态,以便进行调试。这可以帮助您识别与路由更改相关的任何意外行为。示例如下:

import { useLocation } from 'react-router-dom';

const CampaignDetail: React.FC<RouteComponentProps> = (props) => {
  const { title } = useParams<{ title: string }>();
  const location = useLocation();

  React.useEffect(() => {
    // ... Logs for debugging purpose
    console.log('Location:', location);
    console.log('Title:', title);
    // ... You can put rest of your logic here
  }, [location, title]);
 }
ubbxdtey

ubbxdtey2#

看起来,用<Switch>组件 Package 路由可以确保一次只匹配一个路由,并可以防止我所描述的行为。

相关问题