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
相关产品推荐
相关产品推荐

