react-router-dom 路由系统

564 阅读4分钟

页面 Home

const Home = () => {
    return (
        <div>Home 页面</div>
    )
}
export default Home

页面 About

const About = () => {
    return (
        <div>About 页面</div>
    )
}
export default About

一、v5路由配置

1、基本使用

  • src/router/App.tsx

    • exact:使用精准匹配
    • Switch:每次只会渲染一条路由
    • Redirect:重定向
    import { Router, Switch, BrowserRouter, Redirect } from 'react-router-dom';
    import Home from '@/views/Home/index'
    import About from '@/views/About/index'
    function App() {
        // 路由优先级,最上面优先级越高
        return (
            <div className="app">
                <BrowserRouter>
                     <Switch> 
                         <Route exact path="/" component={<Redirect to="/home" />} />
                         <Route exact path="/home" component={Home}  />
                         <Route path="/about" component={About} />
                         <Route path="detail/:id" component={Detail}>
                         <Route render={() => <h1>404</h1>} />
                    </Switch>
                </BrowserRouter>
            </div>
        )
    }
    

2、路由跳转,页面获取路由信息

// localhost:3000/detail/12
import React from 'react'
import { RouteComponentProps } from 'react-router-dom'
interface MathParams {
    id: string
}
export const Detail : React.FC<RouteComponentProps<MathParams>> = (props) => {
    console.log(props.history);
    console.log(props.location);
    console.log(props.match);
    
    // 获取url参数
    console.log(props.match.params.id);
    return <h1>详情页面</h1>
}

同理:类式组件也是通过 props 来传递路由信息

3、跨组件路由信息传递

什么是跨组件路由信息传递,比如 home 页面 可以获取到路由信息,但 header 组件,应该如何获取到路由信息

import React from 'react'
import {} from 'react-router-dom'
import { Header } from '@/component/Header/index.tsx'
export class Home extends React.Component {
    render() {
        return (
          <div className="home">
                <Header>头部</Header>
          </div>
        )
    }
}
import React from 'react';
export const Header : React.FC = () => {
    return (
       <div className="header"></div>
    )
}
  • 方式一:HOC 高阶组件(函数式或类式)
import React from 'react'
import { withRouter } from 'react-router-dom'
const HeaderComponent : React.FC = ({ history, location, match }) => {
    // 得到路由信息
    console.log(history);
    console.log(location);
    console.log(match);
    return (
       <div className="header">
            <span className="home" onClick={() => {history.push("/home")}}>主页</span> 
       </div>
    )
}
export const Header = withRouter(HeaderComponent);
  • 方式二:hook 钩子(函数式组件)
import React from 'react'
import { useHistory, useLocation, useParams, useRouteMatch } from 'react-router-dom'
export const header : React.FC = () => {
     // 所有路由信息
     console.log(useHistory());
     // 当前路由信息
     console.log(useLocation());
     // 当前路由的参数 ?a=1&&b=2 
     console.log(useParams());
     // 当前路由匹配的参数 localhost:3000/:id
     console.log(useRouteMatch());
     return (
       <div className="header">
            <span className="home" onClick={() => {useHistory().push("/home")}}>主页</span> 
       </div>
    )
}

二、v6路由配置方式一

1、基本使用

  • src/router/index.tsx

    • BrowserRouter: History 模式
    • HashRouter:Hash 模式
    • Navigate:路由重定向
    import App from '@/App'
    import Home from '@/views/Home/index'
    import About from '@/views/About/index'
    
    import { BrowserRouter, HashRouter, Routes, Route, Navigate } from 'react-router-dom'
    
    const baseRouter = () => (
      <BrowserRouter>
          <Routes>
              <Routes path="/" element={<App/>}>
                  <Route path="/" element={<Navigate to="/home"/>}></Route> 
                  <Route path="/home" element={<Home/>}></Route>  
                  <Route path="/about" element={<About/>}></Route>  
              </Routes>   
          </Routes>
      </BrowserRouter>
    )
    export default baseRouter
    
  • src/main.tsx

    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import Router from '@/router/index'
    ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
      <React.StrictMode>
         <Router /> 
      </React.StrictMode>
    )
    
  • src/App.tsx

    • Outlet:类似于 <router-view />
    • Link:点击跳转
    import { Outlet, Link } from 'react-router-dom'
    function App() {
      return (
        <div className="App">
           <Link to="/home">Home</Link>
           <Link to="/about">About</Link>
           <Outlet></Outlet>
        </div>
      )
    }
    
    export default App
    
    <Link to={`/detail/${id}`}>detail</Link>
    

    路由跳转及跨组件路由信息传递见v6路由跳转及路由信息获取

三、v6路由配置方式二

1、基本使用

  • src/router/index.tsx

    • lazy:组件懒加载
    • Navigate:重定向

    组件懒加载需要被嵌套在React.Suspense

    import React, { lazy } from 'react'
    import { Navigate } from  'react-router-dom'
    const Home = lazy(() => import('@/views/Home/index'))
    const About = lazy(() => import('@/views/About/index'))
    
    const withLoadingComponent = (component: JSX.Element) => (
      <React.Suspense fallback={<div>Loading...</div>}>
        {component}
      </React.Suspense>
    )
    const routes = [
       {
        path: '/',
        element: <Navigate to="/home" />
       },
       {
        path: '/home',
        element: withLoadingComponent(<Home />)
       },
       {
        path: '/about',
        element: withLoadingComponent(<About />)
       }
    ]
    export default routes
    
  • src/main.tsx

    • BrowserRouter: History 模式
    • HashRouter:Hash 模式
    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import App from './App'
    import { BrowserRouter } from 'react-router-dom'
    
    ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
      <React.StrictMode>
        <BrowserRouter>
           <App />
        </BrowserRouter>
      </React.StrictMode>
    )
    
  • src/App.tsx

    import router from '@/router/index-new'
    import { useRoutes, Link } from 'react-router-dom'
    function App() {
      const outlet = useRoutes(router)
      return (
        <div className="App">
           <Link to="/home">Home</Link>
           <Link to="/about">About</Link>
           {outlet}
        </div>
      )
    }
    
    export default App
    

四、v6路由跳转及路由信息获取

import { useParams, useLocation, useNavigate } from 'react-router-dom'
function App() {
    
    const params = useParams();
    // 当前路由状态
    const location = useLocation();
    const navigate = useNavigate();
    
    return (
        <div className="App">
            <button onClick={() => {navigate("/home")}}>Home</button>
            <button onClick={() => {navigate("/about")}}>About</button>
        </div>
    )
}

五、v5 与 v6 对比

  • v6 全面倒向了函数式组件,废除了useHistory(),取而代之的是useNavigate()
  • v5 将路由信息通过 props 的注入在页面中获取到路由信息
  • v5 组件获取路由信息
    • 类组件或函数式组件:HOC高阶组件(withRouter)通过props来获取historylocationmatch
    • 函数式组件:hook函数useHistoryuseLocationuseParamsuseRouteMatch

钩子函数是没法在类式组件中使用的,故在v6中,如果页面或组件是类式的,无法通过钩子函数来获取路由信息及路由跳转方法

六、解决在v6中不支持类组件

在v6中,是没有 withRouter 函数。但可以利用该思想,将类式组件封装成

  • src/helpers/withRoters.tsx

    import { useParams, useLocation, useNavigate } from 'react-router-dom'
    const withRouter = (component) => {
        const Wrapper = (props) => {
            return <component {...props} navigate={useNavigate()} />
        }
        // Wrapper 就是一个函数组件
        export Wrapper;
    }
    
  • src/view/Home/index.tsx

    import React from 'react'
    import { withRouter } from '@/helpers/withRouter.tsx'
    class HomeComponent extends React.Component {
        this.props.navigate(); // 获取路由信息
        render() {
            return (
              <div className="home"></div>
            )
        }
    }
    export const Home = withRouter(HomeComponent)
    

七、路由鉴权

看到了掘金社区有个小伙伴写的路由鉴权,写的很清晰,简单明了,这里我就不细写,直接引用了 快点这里

小编只是刚入门react,技术不深,如若文章有哪些不对的地方,请大家指出,我会感谢大家的指教,并虚心接受。

最后,希望在看这篇文章的小伙伴,能够来个三连,给个鼓励。