You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router V6中如何获取当前组件的上一个路由路径?

React Router V6 无HOC实现来源路径差异化UI渲染

不需要封装高阶组件,React Router V6 原生能力就可以实现,以下是3种可直接落地的方案:

方案1:使用useLocation配合路由state实现(最推荐)

这是官方原生支持的场景传参方式,代码量最小,逻辑最清晰。
你只需要在跳转到商品详情页时,把来源路径存在路由state里传递即可,不管是组件式跳转还是编程式跳转都支持:

// 收藏页(/mycollection)跳转逻辑
import { Link, useNavigate } from 'react-router-dom';

// 声明式跳转
<Link to="/goods/商品id" state={{ from: '/mycollection' }}>商品卡片</Link>

// 编程式跳转
const navigate = useNavigate();
navigate('/goods/商品id', { state: { from: '/mycollection' } });

搜索结果页(/apiSearchResults)跳转时把state里的from字段改成对应路径即可。
在商品详情页直接读取state判断渲染:

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

export default function GoodsDetail() {
  const { state } = useLocation();
  // 兼容用户直接输入地址进入、state丢失的场景,默认不展示删除按钮
  const showDeleteBtn = state?.from === '/mycollection';

  return (
    <div className="goods-detail">
      {/* 其他通用详情内容 */}
      {showDeleteBtn && <button className="delete-btn">删除</button>}
    </div>
  );
}

方案2:全局维护路由历史栈(无需修改已有跳转逻辑)

如果项目已有大量跳转代码,不想逐个修改加state,可以在全局路由层维护一个路径历史栈,通过Context下发给各页面,直接读取上一个访问路径做判断。
首先在全局路由出口处做监听:

import { useLocation, useOutlet } from 'react-router-dom';
import { createContext, useContext, useEffect, useRef } from 'react';

// 新建路径历史Context
export const PathHistoryContext = createContext([]);

export default function GlobalRouterWrapper() {
  const location = useLocation();
  const outlet = useOutlet();
  // 用ref存历史,避免路径变化时不必要的重渲染
  const pathStack = useRef([location.pathname]);

  useEffect(() => {
    pathStack.current.push(location.pathname);
    // 控制栈长度避免内存占用过高
    if (pathStack.current.length > 100) pathStack.current.shift();
  }, [location.pathname]);

  return (
    <PathHistoryContext.Provider value={pathStack.current}>
      {outlet}
    </PathHistoryContext.Provider>
  );
}

把这个组件放在路由配置的最外层,所有页面都可以拿到访问历史:

// 商品详情页读取历史判断
import { PathHistoryContext } from './GlobalRouterWrapper';

export default function GoodsDetail() {
  const pathStack = useContext(PathHistoryContext);
  // 取栈中倒数第二个值,就是上一个访问的路径
  const prevPath = pathStack[pathStack.length - 2] || '';
  const showDeleteBtn = prevPath === '/mycollection';

  return (
    <div className="goods-detail">
      {/* 通用内容 */}
      {showDeleteBtn && <button className="delete-btn">删除</button>}
    </div>
  );
}

如果用户是从外部站点直接进入详情页,历史栈里只有当前详情页路径,这时候prevPath为空,默认不展示删除按钮,符合常规业务预期。

方案3:路由配置直接传渲染标识(适合嵌套路由场景)

如果你的商品详情页是作为不同父路由的嵌套子路由存在的,可以直接在路由配置里给组件传差异化props,不需要额外判断逻辑:

// 路由配置
const routeConfig = [
  {
    path: '/mycollection',
    element: <MyCollection />,
    children: [
      {
        path: 'goods/:id',
        element: <GoodsDetail showDeleteBtn={true} />
      }
    ]
  },
  {
    path: '/apiSearchResults',
    element: <SearchResults />,
    children: [
      {
        path: 'goods/:id',
        element: <GoodsDetail showDeleteBtn={false} />
      }
    ]
  },
  // 独立访问的详情页默认不展示删除按钮
  {
    path: '/goods/:id',
    element: <GoodsDetail showDeleteBtn={false} />
  }
];

这种方案逻辑最直白,但仅适用于嵌套路由场景,平级路由跳转无法生效。


内容的提问来源于stack exchange,提问作者Iggee Xy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:18:24