React路由监听

文章介绍了在React应用中如何进行路由监听,包括在组件内部使用`props.history.listen()`进行局部监听,以及在App.js中通过`withRouter`实现全局路由监听。局部监听适用于组件离开时的特定操作,而全局监听则能捕获应用内的所有路由变化。

(一): 局部路由监听: 
1, 在路由跳转的组件中使用props.history.listen() 监听路由, 得到返回值cancle
this.cancle = props.history.listen((route, type)=>{})
 
2, 在组件的componentWillUnmount中取消路由监听, 调用 cancle函数, 以防止重复监听,浪费性能
this.cancle()

注: 局部监听只能监听此组件离开时的路由, 类似于vue中beforeRouteLeave() 路由守卫


(二): 全局路由监听: 
1, 在app.js中从路由模块导入withRouter 
import { withRouter } from 'react-router-dom'

2, 导出App时,用withRouter 函数处理后导出, 把路由数据添加到props中
export default withRouter(App);

3, 在app根组件的componentDidMount函数中添加全局路由监听
 componentDidMount() {
    console.log(this.props)
    this.props.history.listen(path=>{
      console.log("全局路由监听" + path.pathname)
    })
  }

注: 全局路由监听,根组件App中没有路由信息, 需要使用高阶组件withRouter添加路由信息,然后监听

<think> 我们被要求回答在React 18中监听路由变化的方法。根据提供的引用,我们可以总结几种方法,并结合React 18的特点(如并发模式)给出建议。 注意:React 18本身并没有直接提供路由监听的功能,路由监听通常由路由库(如react-router)提供。因此,我们的方法将基于react-router(当前主流版本是v6)来实现。 根据引用内容,我们可以归纳几种监听路由变化的方法: 1. 使用react-router的hooks(如useLocation)结合useEffect(引用[2])。 2. 使用自定义事件监听(引用[2]提到但不依赖react-router内部机制,但引用中没有具体代码,所以我们重点放在react-router提供的方法)。 3. 使用高阶组件withRouter(引用[3][4][5]),但注意在react-router v5中可用,在v6中已被移除。 由于React 18推荐使用函数组件和hooks,且react-router v6已不再支持withRouter,因此我们主要介绍使用hooks的方法。 另外,引用[3][4][5]中提到在类组件中使用withRouter的方法,但考虑到v6中已移除,如果用户使用v6,则类组件需要采用其他方式(如使用包装函数)。 因此,我们重点介绍react-router v6(适用于React 18)中的路由监听方法。 方法一:使用useLocation和useEffect(函数组件) 步骤: 1. 从'react-router-dom'导入useLocation。 2. 在函数组件中调用useLocation()获取location对象。 3. 使用useEffect,将location作为依赖项,这样当location变化时(即路由变化),useEffect的回调就会执行。 方法二:使用useNavigationType(获取导航类型,如POP, PUSH, REPLACE) 1. 从'react-router-dom'导入useNavigationType。 2. 在函数组件中调用useNavigationType(),可以得到当前导航的类型。 方法三:使用Listeners(在路由上下文之外监听,例如在模块中) 在react-router v6中,我们可以使用history对象(通过createBrowserHistory创建)来监听,但注意v6推荐使用新的API,且通常我们不需要直接创建history对象,因为路由组件已经提供了。不过,如果我们想全局监听(如在Redux中),可以使用history包。 但是,在react-router v6中,我们不鼓励直接使用history包,而是使用路由库提供的hooks和组件。如果需要在非组件环境中监听,可以采用以下方法: 使用history包(独立于react-router): 1. 安装history包:`npm install history` 2. 创建一个history对象:`import { createBrowserHistory } from 'history'; const history = createBrowserHistory();` 3. 然后添加监听:`history.listen(({ location, action }) => { ... });` 注意:在react-router v6中,我们通常使用<BrowserRouter>,它会创建一个全局的history对象,但我们无法直接获取到它(与v5不同)。因此,如果我们想全局监听,可能需要自己创建history对象并将其传递给<Router>,而不是使用<BrowserRouter>。 具体步骤(使用自定义history对象): 1. 创建一个history对象(使用history包)。 2. 将<Router>组件(不是BrowserRouter)包裹在应用外层,并将history对象作为prop传入。 3. 然后就可以在这个history对象上添加监听器。 但是,在React 18中,使用react-router v6,官方推荐使用新的数据路由API(createBrowserRouter等),这时我们可以通过router.subscribe来监听。 方法四:使用react-router v6的useBeforeUnload和useBlocker(用于特定场景)可能不太适合一般的监听,这里不展开。 考虑到用户可能仍在用传统的<BrowserRouter>方式,我们分别给出两种场景的监听方法。 总结: - 在函数组件内:使用useLocation和useEffect。 - 在类组件中(使用v6):由于v6移除了withRouter,我们可以自定义一个高阶组件,利用useLocation(但hooks不能在类组件中使用),所以我们可以将类组件包装在函数组件中,或者使用context(复杂)。因此,建议将类组件改为函数组件,或者使用自定义history对象。 - 全局监听(非组件):使用自定义history对象,并将其用于路由。 下面我们给出具体代码示例。 注意:React 18和react-router v6是目前推荐的新项目配置。 示例1:函数组件内监听路由变化 ```jsx import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function MyComponent() { const location = useLocation(); useEffect(() => { // 当location变化时执行 console.log('Route changed to', location.pathname); // 这里可以执行一些副作用,例如数据获取等 }, [location]); // 依赖location对象 return ( // ...组件内容 ); } ``` 示例2:在类组件中监听(使用自定义高阶组件) 由于react-router v6不再提供withRouter,我们可以自己创建一个: ```jsx import { useLocation } from 'react-router-dom'; import React from 'react'; export function withRouter(Component) { return function WrappedComponent(props) { const location = useLocation(); return <Component {...props} location={location} />; }; } ``` 然后在类组件中使用: ```jsx import React from 'react'; import { withRouter } from './withRouter'; // 上面定义的高阶组件路径 class MyClassComponent extends React.Component { componentDidUpdate(prevProps) { if (this.props.location !== prevProps.location) { console.log('Route changed', this.props.location); } } render() { // ... } } export default withRouter(MyClassComponent); ``` 示例3:全局监听(使用自定义history对象) 步骤1:创建history对象并导出(在一个单独的文件中,例如history.js) ```javascript import { createBrowserHistory } from 'history'; export const history = createBrowserHistory(); ``` 步骤2:在入口文件(如index.js)中使用<Router>而不是<BrowserRouter> ```jsx import React from 'react'; import ReactDOM from 'react-dom/client'; import { Router } from 'react-router-dom'; import { history } from './history'; // 导出自定义history对象 import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Router location={history.location} navigator={history}> <App /> </Router> ); ``` 步骤3:在任何地方(如一个js模块中)监听路由变化 ```javascript import { history } from './history'; // 添加监听 const unlisten = history.listen(({ location, action }) => { console.log('Route changed to', location.pathname, action); }); // 取消监听(在需要的时候) // unlisten(); ``` 注意:在React 18中,使用新的根API(ReactDOM.createRoot)进行渲染。 另外,关于React 18的并发模式(Concurrent Mode),这些监听方法都是安全的,因为它们都是基于React的副作用处理机制(如useEffect)或原生事件监听。 最后,我们强调,在React 18和react-router v6中,优先推荐使用hooks(函数组件)的方式。 根据引用[1],我们还要注意性能:避免在每次路由变化时执行过重的操作,并注意清理副作用(在useEffect的清理函数中)。 因此,针对用户的问题,我们给出以上方法。 </think> 在 React 18 中监听路由变化主要有以下几种实现方法,结合路由库的最佳实践: ### 📍 一、使用 `react-router` Hooks(推荐) ```jsx import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function App() { const location = useLocation(); // 获取 location 对象 useEffect(() => { // location 变化时触发(包含 pathname/search/hash/state 等) console.log('路由变化:', location.pathname); // 执行数据加载或追踪逻辑 }, [location]); // 依赖 location 对象 return <>{/* 组件内容 */}</>; } ``` **原理**: `useLocation` Hook 返回当前路由信息对象,当其属性变化时触发 `useEffect` 执行[^2]。 ### 📍 二、自定义历史对象监听(全局监听) ```javascript // 1. 创建 history 实例 (history v5) import { createBrowserHistory } from 'history'; export const customHistory = createBrowserHistory(); // 2.路由配置中使用 import { Router } from 'react-router-dom'; <Router history={customHistory}> <App /> </Router> // 3. 任意位置添加监听 customHistory.listen(({ location, action }) => { console.log(`路由变化: ${action} -> ${location.pathname}`); }); ``` **优势**: 可在非组件环境(如 Redux store)监听路由变化[^2]。 ### 📍 三、类组件监听方案(兼容旧版) ```jsx import { withRouter } from 'react-router-dom'; class App extends React.Component { componentDidUpdate(prevProps) { if (this.props.location !== prevProps.location) { console.log('路由变化:', this.props.location.pathname); } } render() { /* ... */ } } export default withRouter(App); // 注入路由属性 ``` **注意**: `withRouter` 在 react-router v6 中已移除,需自行实现高阶组件或升级到 Hooks[^4][^5]。 --- ### ⚠️ 关键注意事项(React 18) 1. **严格模式处理**: React 18 严格模式会模拟组件卸载,需在 `useEffect` 清理函数中移除外部监听: ```javascript useEffect(() => { const unlisten = history.listen(callback); return () => unlisten(); // 清理监听器 }, []); ``` 2. **路由库版本**: - 使用 `react-router-dom v6+` 时优先采用 Hooks API - v5 用户可继续使用 `withRouter` 或上下文 API 3. **性能优化**: 避免在路由监听中执行重渲染操作,可通过 `useMemo` 优化依赖项: ```javascript useEffect(() => { // 仅当 pathname 变化时执行 }, [location.pathname]); ``` ### 🌰 完整函数组件示例 ```jsx import { useEffect } from 'react'; import { useLocation, useNavigationType } from 'react-router-dom'; export default function RouteListener() { const location = useLocation(); const action = useNavigationType(); // POP/PUSH/REPLACE useEffect(() => { const analyticsData = { path: location.pathname, search: location.search, action // 导航动作类型 }; console.log('路由事件:', analyticsData); // 发送分析数据或更新状态 }, [location, action]); return null; } ``` > **路由监听的最佳实践**:主要用于埋点统计、页面滚动复位、权限验证或数据预加载等场景,避免在监听器中执行阻塞性操作以保证路由切换流畅性[^1][^2]。 --- ### 相关问题 1. React 18 中路由监听是否影响并发模式(Concurrent Mode)的运行? 2. 如何在 Next.js 框架中实现路由变化监听? 3. 路由监听与性能优化的冲突如何解决? 4. 如何区分用户主动导航和浏览器返回触发的路由变化? 5. 在不使用 `react-router` 的情况下如何监听 hash 路由变化? [^1]: 路由监听React 项目中不可忽视的关键环节,合理使用可提升用户体验 [^2]: `useEffect` 依赖 `location` 对象实现监听react-router 推荐方案 [^3]: 使用自定义 `history` 对象可实现全局路由监听 [^4]: 类组件可通过高阶组件获取路由属性实现监听 [^5]: 在入口文件注入路由属性是兼容旧版方案
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值