《二》React Router 手动路由的跳转、路由参数的传递、路由的嵌套、路由懒加载、通过配置的方式使用路由

手动路由的跳转:

上面的跳转,都必须通过点击 link 组件才能实现。

如果想通过 JS 手动跳转,分为两种情况:

  1. 在函数组件中:React Router 提供了一个 useNavigate Hook,调用 useNavigate() 会返回一个对象,返回的对象是一个函数,调用该函数,并且传入路径即可实现手动跳转。
    import React from 'react'
    // 1. 从 react-router-dom 引入 useNavigate 这个 Hook
    import {useNavigate} from 'react-router-dom'
    
    function About() {
      // 2. 调用 useNavigate,会返回一个对象,返回的对象是一个函数
      const navigate = useNavigate()
    
      const handleNavToHome = () => {
        // 3. 调用返回的函数,实现手动跳转。第一个参数是要跳转的路径,第二个参数是非必填的配置项;或者参数也可以传入一个数字,表示前进或者后退
        navigate('/home')
      }
    
      return (
        <h1 onClick={handleNavToHome}>About</h1>
      )
    }
    
    export default About
    
  2. 在类组件中:React Router 没有提供在类组件中可以实现手动跳转的 API,可以用原生 JS (例如:window.location 等)来实现或者通过高阶组件来对类组件进行增强。

    React Router V5 中本身就是有 withRouter 这个高阶组件的。

    // hoc/WithRouter.jsx
    import {useNavigate} from 'react-router-dom'
    
    // 封装一个高阶组件来使类组件中可以获取到 navigate
    function WithRouter(WrapperComponent) {
      // 返回一个新的函数组价
     function EnhanceComponent(props) {
      	// 在函数组件中调用 useNavigate Hook,将结果作为 props 传入
        const navigate = useNavigate()
        const router = {navigate}
        return <WrapperComponent {...props} router={router} />
      }
      return EnhanceComponent
    }
    
    export default WithRouter
    
    // Home.jsx
    import React, {PureComponent} from 'react'
    
    import WithRouter from './hoc/WithRouter'
    
    class Home extends PureComponent {
      handleNavToAbout = () => {
        this.props.router.navigate('/about')
      }
    
      render() {
        return (
          <div>
            <h1 onClick={this.handleNavToAbout}>Home</h1>
          </div>
        )
      }
    }
    
    export default WithRouter(Home)
    

路由参数的传递:

  1. 通过动态路由的方式。

    动态路由指的是路由中的路径并不会固定。
    例如:/about 的路径对应一个组件 About。如果在配置 Route 时将 path 写成 /about/:userId,那么路径 /about/1/about/2 都可以匹配到该 Route,About 组件将都可以显示。这个路由就称为动态路由。
    可以使用动态路由来为路由传递参数。

    // App.jsx
    import React, {PureComponent} from 'react'
    import {Routes, Route, Link} from 'react-router-dom'
    
    import Home from './components/Home'
    import About from './components/About'
    
    class App extends PureComponent {
      render() {
        return (
          <div>
            <div>
              <Link to='/home'>首页</Link>
              {/* 1. 传递参数 */}
              <Link to='/about/123'>关于</Link>
            </div>
    
            <Routes>
              <Route path='/home' element={<Home/>} />
              {/* :userId 匹配动态路由 */}
              <Route path='/about/:userId' element={<About/>} />
            </Routes>
          </div>
        )
      }
    }
    
    export default App
    
    // About.jsx
    import React from 'react'
    import {useParams} from 'react-router-dom'
    
    function About() {
      // 2. 获取参数。调用 useParams Hook 会返回一个对象,返回的对象中就包含动态路由中的参数
      const params = useParams()
      const userId = params.userId
      
      return (
        <h1>About:{userId}</h1>
      )
    }
    
    export default About
    
  2. 通过 search 传递参数。
    // App.jsx
    import React, {PureComponent} from 'react'
    import {Routes, Route, Link} from 'react-router-dom'
    
    import Home from './components/Home'
    import About from './components/About'
    
    class App extends PureComponent {
      render() {
        return (
          <div>
            <div>
              <Link to='/home'>首页</Link>
              {/* 1. 传递参数。将 search 拼接在路径后面 */}
              <Link to='/about?userId=123'>关于</Link>
            </div>
    
            <Routes>
              <Route path='/home' element={<Home/>} />
              <Route path='/about' element={<About/>} />
            </Routes>
          </div>
        )
      }
    }
    
    export default App
    
    // About.jsx
    import React from 'react'
    import {useSearchParams, useLocation} from 'react-router-dom'
    
    function About() {
      // 2. 获取参数。调用 useSearchParams Hook
      const [searchParams] = useSearchParams()
      const userId = searchParams.get('userId')
    
      // 也可以调用 useLocation Hook,就可以获取到 search,但是是一个字符串,还需要再进行转换
      // const location = useLocation() // 通过 location.search 就可以获取到 ?userId=123
     
      return (
        <h1>About:{userId}</h1>
      )
    }
    
    export default About
    

路由的嵌套:

路由是可以嵌套的。被嵌套的子路由,配置路径和组件的映射关系需要直接写在父路由下;使用 <Outlet /> 组件作为在父路由元素中子路由元素的占位元素,被嵌套的子路由的路径匹配上后,子路由的元素将会显示在 <Outlet /> 的位置。

React Router V5 中被嵌套的子路由,配置路径和组件的映射关系直接写在父路由的元素中。
React Router V6 中改为直接放置在父路由下,是为了统一、方便管理。

例如:有一个首页按钮和一个关于按钮,分别可以跳转到 Home 页和 About 页;然后在 Home 页又有一个首页推荐按钮和一个首页排行榜按钮,分别可以跳转到 HomeRecommend 页和 HomeRanking 页。这就是两级的路由嵌套。

// App.jsx
import React, {PureComponent} from 'react'
import {Routes, Route, Link} from 'react-router-dom'

import Home from './components/Home'
import About from './components/About'
import HomeRecommend from './components/HomeRecommend'
import HomeRanking from './components/HomeRanking'

class App extends PureComponent {
  render() {
    return (
      <div>
        <div>
          <Link to='/home'>首页</Link>
          <Link to='/about'>关于</Link>
        </div>

        <Routes>
          <Route path='/home' element={<Home/>}>
             {/* 1. 被嵌套的子路由,配置路径和组件的映射关系写在父路由下。统一写在此处,方便管理 */}
            <Route path='/home/recommend' element={<HomeRecommend />} />
            <Route path='/home/ranking' element={<HomeRanking />} />
          </Route>
          <Route path='/about' element={<About/>} />
        </Routes>
      </div>
    )
  }
}

export default App
import React, {PureComponent} from 'react'
import {Link, Outlet} from 'react-router-dom'

class Home extends PureComponent {
  render() {
    return (
      <div>
        <h1>Home</h1>
        <div>
          <Link to='/home/recommend'>首页推荐</Link>
          <Link to='/home/ranking'>首页排行榜</Link>
        </div>

        {/* 2. 子路由元素的占位元素。被嵌套的子路由的路径匹配上后,子路由的元素将会显示在此处 */}
        <Outlet />

        {/* React Router V5 中被嵌套的子路由,配置路径和组件的映射关系直接写在父路由的元素中 */}
        {/* <div>
          <Route path='/home/recommend' component={<HomeRecommend />} />
          <Route path='/home/ranking' component={<HomeRanking />} />
        </div> */}
      </div>
    )
  }
}

export default Home

请添加图片描述

路由懒加载:

import {Link, Routes, Route} from 'react-router-dom'

// 路由同步加载,打包的时候所有文件将都会被打包到一个 JS 中
import Home from './components/Home'
import About from './components/About'
import NotFound from './components/NotFound'

function App() {
  return (
    <div>
      <div>
        <Link to='/home'>首页</Link>
        <Link to='/about?userId=123'>关于</Link>
      </div>

      <Routes>
        <Route path='/home' element={<Home />} />
        <Route path='/about' element={<About />} />
        <Route path='*' element={<NotFound />} />
      </Routes>
    </div>
  )
}

export default App

请添加图片描述

路由懒加载之后,打包的时候就可以进行分包处理,对其对应的文件进行单独打包,打包到一个单独的 JS 文件中。

React Router 的路由懒加载不是 React Router 提供的功能,而是借助 React 提供的 React.lazy() 来实现。 React.lazy() 需要传入一个函数作为参数,在函数内部可以使用 import() 来异步加载文件。

import() 可以在需要的时候,再加载某个模块;并且 Webpack 检测到 import() ,就会对其进行引入的文件进行单独打包。

// index.js
import {Suspense} from 'react'
import ReactDOM from 'react-dom/client'
import {HashRouter} from 'react-router-dom'

import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <HashRouter>
    {/* 1. 由于路由懒加载,可能会出现某些组件需要加载的时候还没有下载下来的情况,导致报错。因此使用 Suspense 组件包裹根组件,并且传入 fallback。在异步的组件还没下载完成、加载出来的时候,就会先显示 fallback 中传入的内容 */}
    <Suspense fallback={<h1>Loading</h1>}>
      <App />
    </Suspense>
  </HashRouter>
)
// App.jsx
import React from 'react'
import {Link, Routes, Route} from 'react-router-dom'

import Home from './components/Home'

// 2. 使用 React.lazy() 实现路由懒加载,在需要的时候才加载组件
const About = React.lazy(() => import('./components/About'))
const NotFound = React.lazy(() => import('./components/NotFound'))

function App() {
  return (
    <div>
      <div>
        <Link to='/home'>首页</Link>
        <Link to='/about?userId=123'>关于</Link>
      </div>
      <Routes>
        <Route path='/home' element={<Home />} />
        <Route path='/about' element={<About />} />
        <Route path='*' element={<NotFound />} />
      </Routes>
    </div>
  )
}

export default App

请添加图片描述

通过配置的方式使用路由:

React Router V5 中想要通过配置的方式使用路由,需要单独安装一个 react-router-config 库。

// config.routers.js
import Home from '../components/Home'
import About from '../components/About'
import HomeRecommend from '../components/HomeRecommend'

// 1. 配置路由
const routers = [
  // 一级路由
  {
    path: '/home',
    element: <Home />,
    // 通过 children 配置嵌套的二级路由
    children: [
      {
        path: '/home/recommend',
        element: <HomeRecommend />,
      }
    ]
  },
  {
    path: '/about',
    element: <About />,
  },
]

export default routers
// App.jsx
import {Link, useRoutes} from 'react-router-dom'

import routers from './config/routers'

function App() {
  return (
    <div>
      <div>
        <Link to='/home'>首页</Link>
        <Link to='/about?userId=123'>关于</Link>
      </div>

      {/* 2. 调用 useRoutes Hook,传入路由的配置信息,渲染出来的其实下面下面注释掉的内容 */}
      {useRoutes(routers)}

      {/* <Routes>
        <Route path='/home' element={<Home />}>
          <Route path='/home/recommend' element={<HomeRecommend />} />
        </Route>
        <Route path='/about' element={<About />} />
      </Routes> */}
    </div>
  )
}

export default App
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值