react-router-dom v5 使用 history.push() 无法实现路由跳转的问题解决方法

问题描述

我正在实现日志跳转的任务,因为有多个模块用到了日志,需要实现各个日志的互相跳转。
列表页
在这里插入图片描述
详情页
在这里插入图片描述

目前结构大概描述一下,比如说,任务式建模和notebook里面会有列表页,每个列表里面都会有很多任务,任务点进去后会有一个Tab页是日志页面
然后问题出现了

  1. 当我从 「任务式建模」里面某个任务的日志页面,跳转到「Notebook」里面某个任务的日志页面的时候,一切正常。
  2. 而当我从「任务式建模」里面某个任务的日志界面,跳到「任务式建模」里面另外一个任务的日志界面时,点击了后发现url发生了改变,但是页面却没有发生变化。自己手动刷新后会跳转到正确的页面(但是这样子肯定不行)
    在url上面的变化可以看这张图
    在这里插入图片描述

解决过程/思路

百度上尝试了很多别人发的方法,包括但不限于

  1. 禁用严格模式—我这边本身没有开严格模式——失败
  2. 将路由组件的删除,只在App组件包裹 —— 用的是公司包装过的路由组件,且确实也只包了一层。失败
  3. 尝试先跳转到一个白屏页面(我尝试的是跳转到列表页),然后再跳转回来——可以实现,但是很不优雅,而且这样子的话如果同时使用浏览器右上角的前进后退,会导致出现很混乱的后果
  4. 使用window.location.href(url),可以跳,但是会导致页面的刷新。不符合我的业务逻辑。

最终排查出来的问题所在:

最后发现:其实是路由路径匹配方面出现的问题

分析

我项目里面的路由层级是这样子的

第一层路由


const routes = {
  [BASE_NAME]: {
    title: t('腾讯云 TI 平台 TI-ONE - 控制台'),
    component: RouteWrapper,
  },
};

export default routes;

第二层路由(部分)

// 二级以上路由应用内注册
const routes = {

  '/job': {
    title: t('任务式建模 - 训练工坊 - 腾讯云 TI 平台 - 控制台'),
    component: Job,
  },
  '/notebook': {
    title: t('Notebook - 训练工坊 - 腾讯云 TI 平台 - 控制台'),
    component: Notebook,
  },
  // 批量预测
  ...BatchPredictionsRoutes,
  ...AIMarketRoutes,
  // 可视化建模
  ...DesignerRoutes,
  // 数据标注
  ...DataPipelineRoutes,
  // 模型评测
  ...EvaluationRoutes,
};

第三层路由(以任务式建模Job为例)

import React from 'react';
import { Switch, Route, useRouteMatch } from 'react-router-dom';
import { Redirect } from '@src/components';

import List from './List';
import Create from './Create';
import Detail from './Detail';
import Tensorboard from './Tensorboard';

export default function Router(): JSX.Element {
  const match = useRouteMatch();
  return (
    <Switch>
      <Redirect exact from={`${match.url}`} to={`${match.url}/list`} />
      <Route exact path={`${match.path}/create`}>
        <Create operation="create" />
      </Route>
      <Route exact path={`${match.path}/copy/:trainingTaskId`}>
        <Create operation="copy" />
      </Route>
      <Redirect exact from={`${match.url}/copy`} to={`${match.url}/list`} />
      <Redirect exact from={`${match.url}/detail`} to={`${match.url}/list`} />
      <Route exact path={`${match.path}/detail/:trainingTaskId`} component={Detail} />
      <Route exact path={`${match.path}/list`} component={List} />
      <Route exact path={`${match.path}/tensorboard/:trainingTaskId`} component={Tensorboard} />
    </Switch>
  );
}

我们重点看一下详情页

<Route exact path={`${match.path}/detail/:trainingTaskId`} component={Detail} />

他的path只匹配到detail(再后面这个:trainingTaskId是params参数),结合这张图可以看到,当我同一个版块不同日志之间跳转的时候,一直到detail,他是都不变化的。所以虽然我用history.push(url)会造成url的变化,但是路由以为他还是同一个路由页面,因此不会进行路由的跳转。
在这里插入图片描述

解决方法

F1:给路由组件(我这里是Detail组件)里面加上key

  return (
    <MainLayout
      showBackButton
      onBackButtonClick={handleOnGoBack}
      title={getTitle()}
      {...getDocInfo()}
      key={trainingTaskId} // 修改的地方
    >
「xxxx」
    </MainLayout>
    )

具体代码就不贴了,针对这个问题,唯一的修改点就在于这个key。添加上key之后,当我push之后,路由就会发现,这两个不是同一个页面,然后就会使组件进行重新挂载
个人理解:添加上key之后,在进行跳转的时候,React就可以识别出来这两个不是同一个路由组件了,然后在重排(回流)的时候就会更新路由组件的内容

F2:在路由匹配的时候就加上key(未验证,问的GPT)

GPT的解释

你遇到的问题是由于 React Router 在同一路由路径下切换时不会重新挂载组件,导致组件不会重新渲染。为了在同一路由路径下切换时强制重新渲染组件,你可以使用 key 属性来强制 React 重新挂载组件。

你可以在 Route 组件上使用 key 属性,并将 trainingTaskId 作为 key 的一部分。这样,当 trainingTaskId 变化时,React 会认为这是一个新的组件实例,从而重新挂载组件。

GPT的解决方法

<Route
        exact
        path={`${match.path}/detail/:trainingTaskId`}
        render={({ match }) => (
          <Detail key={match.params.trainingTaskId} trainingTaskId={match.params.trainingTaskId} />
        )}
      />

over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值