React-Router

360 阅读3分钟

路由

  • 官网地址

  • 路由:根据路由地址匹配组件的路由

  • 安装:

    npm install react-router-dom@6
    

路由初体验

// 入口文件index.js

...
// 1.引入路由,选择路由模式
import { BrowserRouter } from 'react-router-dom'
...
root.render(
    <!-- 2.使用该路由模式 -->
    <BrowserRouter>
        <App />
    </BrowserRouter>
)
// 路由表

// 引入路由
import { Routes, Route,Link } from 'react-router-dom'
// Routes:路由表(路由对象) Route:路由信息 Link:相当于a标签
// 引入组件
import Index from './views/Index/index'
import Login from './views/Login/index'
function App() {
    return (
        <div>
        	<div>
                <Link to='/'>首页</Link> | <Link to='/login'>登录</Link>
            </div>
            <!-- 路由表 -->
            <Routes>
            	<Route path='/' element={<Index></Index>}></Route>
           		<Route path='/login' element={<Login></Login>}></Route>
            </Routes>
        </div>
    )
}
export default App

路由模式

  • 两种路由模式

    • hashHashRouter
    • historyBrowserRouter
    #*****
    两种路由模式的区别:
    答:
    `hash`:虽然出现在URL中,但不会被包括在HTTP,每次页面切换其实切换的是'#'之后的内容,而'#'后内容的改变并不会触发地址的改变,所以不存在发出请求,对后端完全没有影响,因此改变hash不会重新加载页面
    `history`:利用了浏览器的历史记录栈,可以通过前进 后退控制页面的跳转,刷新是真实的改变url
    
  • 引入

    import { BrowserRouter, HashRouter } from "react-router-dom";
    

    BrowserRouter,HashRouter 都是组件

  • 使用

    <!-- history模式 -->
    <BrowserRouter>
        <App />
    </BrowserRouter>
    <!-- hash模式 -->
    <BrowserRouter>
        <App />
    </BrowserRouter>
    

全局组件

  • 路由( **react-router-dom **)提供的全局组件

  • 引入:

    import {Routes,Route,Link,Outlet} from 'react-router-dom'
    
  • Routes:创建路由表(路由对象)

  • Route:创建路由信息

    • path:跳转的目标路由地址
    • element:显示的组件
  • Link:路由a标签

    • to:跳转的目标路由地址
  • Outlet:路由视图占位符

路由跳转(useNavigate)

  • push:浏览器历史栈有记录的跳转,可回退

  • replace:历史栈没有记录,不可回退

  • go:前进和后退

  • 语法

    • 引入:

      import {useNavigate} from 'react-router-dom'
      
    • 使用:

      let navigate = useNavigate()
      
      • 注意:路由hooks必须写到组件中

      • useNavigate()

        `useNavigate()`的返回值是一个方法,方法有2个参数
        参数1:路由url
        参数2:配置项(用来改变跳转方式和传递参数),是个对象
        	{
                replace:true, //replace跳转
                state:{} // params传参
            }
        
        // push语法(默认为push)
        navigate('/login')
        // replace语法
        navigate('/login',{replace:true})
        // go语法
        navigate(2) //前进2个页面
        navigate(-2) //后退2个页面
        

路由传参

  • 路由地址可见(query参数)

    • 字符串模板拼接
    function Index(){
        let navigate = useNavigate()
        let age=12
        const btn()={
            navigate('/home?name=小灰灰&&age=${age}')
        }
        return(
            <button onClick={()=>btn()}>query传参</button>
        )
    }
    
  • 路由地址不可见(params传参)

    • 使用 useNavigate() 返回的方法的配置项(参数2)的 state 属性
    function Index(){
        let navigate = useNavigate()
        let age=12
        const btn()={
            navigate('/home',{
            	state:{age:14}
            })
        }
        return(
            <button onClick={()=>btn()}>params传参</button>
        )
    }
    

获取路由参数uselocation

  • 获取(query)参数

    • 使用第三方库 query-string 解析 query 参数

      1.安装 `npm install  query-string`
      2.在需要解析的地方引入 `import qs from 'query-string';`
      3.使用qs.parse解析 `qs.parse(需要解析的query参数)`
      
    • 使用 react-router-dom 提供的 useLocation 来获取路由信息

      1.引入 `import {useLocation} from 'react-router-dom'`
      2.使用 `let location = useLocation()`
      
    • 使用 location.search 获取query参数

    import { useNavigate, useLocation } from "react-router-dom"; // 引入路由提供的hooks
    import qs from "query-string"; // 引入解析参数的第三方库
    function Me() {
        let navigate = useNavigate() // 路由跳转
        let location = useLocation() // 路由信息
        console.log(location); // 路由信息
        console.log(location.search); // 参数
        console.log(qs.parse(location.search)); //解析后的参数
        return (
            <div>
                <h1>我的</h1>
                <button onClick={() => navigate('/home')}>去首页</button>
            </div>
        )
    }
    
  • 获取(params)参数

    • 使用 location.state 获取params参数
    import { useNavigate, useLocation } from "react-router-dom"; // 引入路由提供的hooks
    function Me() {
        let navigate = useNavigate() // 路由跳转
        let location = useLocation() // 路由信息
        console.log(location); // 路由信息
        console.log(location.state); // 参数
        console.log(location.state); //解析后的参数
        return (
            <div>
                <h1>我的</h1>
                <button onClick={() => navigate('/home')}>去首页</button>
            </div>
        )
    }
    

路由模块化

  • 在路径 src/router/index.js 中创建路由表,路由表也是一个组件
  • 再到根组件中进行引入,使用路由表这个组件
import Index from '../views/Index/index'
import Me from '../views/Me/index'
function RouterList(){
    return (
        <Routes>
        	<Route path="/" element={<Index></Index>}></Route>
        	<Route path="/me" element={<Me></Me>}></Route>
        </Routes>
    )
}
export default RouterList

嵌套路由

  • 配置嵌套路由

    • 在路由组件中进行嵌套,直接添加路由信息
    • 嵌套路由的路由url会自动与父级路由url进行拼接
    • 在父级路由组件中使用路由占位符 <Outlet> 展示嵌套路由组件
    <Routes>
        <Route path="/" element={<Index></Index>}>
            <!-- 嵌套路由 -->
            <Route path="/indexshow" element={<IndexShow></IndexShow>}></Route>
        </Route>
        <Route path="/home" element={<Home></Home>}></Route>
    </Routes>
    
  • 展示嵌套路由

    return(
        <div>
            <h1>index</h1>
            <!-- 展示嵌套路由 -->
            <Outlet></Outlet>
        </div>
    )
    

路由重定向

  • 使用自定义hooks
// 引入路由跳转和路由信息
import { useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";
function useRedirect() {
    let location = useLocation() //路由信息
    let navigate = useNavigate() //路由跳转
    console.log('路由当前', location.pathname);
    // 监听当前路由
    useEffect(() => {
        if (location.pathname == '/') {
            navigate('/home') //重定向
        }
    }, [location.pathname])
}
export default useRedirect

路由守卫

  • 作用:时刻监听着路由地址的改变
// 例:校验是否登录
import { useNavigate, useLocation } from "react-router-dom"; // 引入路由跳转和路由信息
import { useEffect } from "react"; // react的hooks
function useBeforEach(params) {
    let navigate = useNavigate() //路由跳转
    let location = useLocation() //路由信息
    // 监听路由
    useEffect(() => {
        if (location.pathname != '/login') {
            if (!sessionStorage.getItem('token')) {
                navigate('/login')
            }
        }
    }, [location.pathname])
}
export default useBeforEach
  • 由于路由守卫和路由重定向都需要监听路由信息,所以可以进行合并
import { useLocation, useNavigate } from "react-router-dom"; // 导入路由信息和路由跳转
import { useEffect } from "react"; //react的hooks
function useRedBef() {
    let location = useLocation() //路由信息
    let navigate = useNavigate() //路由跳转
    // 监听路由
    useEffect(() => {
        // 1.判断是否内部页面
        if (location.pathname != '/login') {
            // 2.路由守卫
            if (sessionStorage.getItem('token')) {
                // 3.重定向
                if (location.pathname == '/') {
                    navigate('/home')
                }
            } else {
                navigate('/login')
            }
        }
    }, [location.pathname])
}
export default useRedBef

404页面

<Route path='*' element={<NotFind ></NotFind >}></Route>

首页白屏

  • 配合 路由懒加载 使用

  • 语法

    <Suspense fallback={先展示的组件}>
    	<!-- 路由表 -->
    </Suspense>
    

路由懒加载

  • 项目启动时不会加载所有页面,而是按需加载,提高了项目首次加载的速度

  • 语法:

    React.lazy(()=>import('组件路径')) // 返回路由懒加载数据
    
  • 结合首页白屏

    • 语法:
      <Suspense fallback={先展示的组件}>
      	<!-- 路由表 -->
      </Suspense>
      
import { Routes, Route, Link } from "react-router-dom"; // 引入路由全局组件
import React, { Suspense } from "react"; // react方法和首页白屏
// 懒加载组件
let Index = React.lazy(() => import('../views/Index/index'))
let Login = React.lazy(() => import('../views/Login/index'))
let Me = React.lazy(() => import('../views/Me/index'))
function RouterList() {
    return (
        <div>
            <!-- 首页白屏 -->
            <Suspense fallback={<div className="aa">loading...</div>}>
                <Routes>
                    <Route path='/home' element={<Index />}></Route>
                    <Route path='/login' element={<Login />}></Route>
                    <Route path='/me' element={<Me />}></Route>
                    <Route path='*' element={<h1>404</h1>}></Route>
                </Routes>
            </Suspense>
        </div>
    );
}
  • 封装自动处理懒加载组件

    import { Routes, Route, Link } from "react-router-dom"; // 引入路由全局组件
    import React, { Suspense } from "react"; // react方法和首页白屏
    // 自动处理懒加载组件
    function AutoLazy(name){
        let Com
        Com = React.lazy(()=>import(`../views/${name}/index`)) // 返回懒加载组件
        return <Com></Com>
    }
    function RouterList() {
        return (
            <div>
                <!-- 首页白屏 -->
                <Suspense fallback={<div className="aa">loading...</div>}>
                    <Routes>
                        <Route path='/home' element={AutoLazy('Index')}></Route>
                        <Route path='/login' element={AutoLazy('Login')}></Route>
                        <Route path='/me' element={AutoLazy('Me')}></Route>
                        <Route path='*' element={<h1>404</h1>}></Route>
                    </Routes>
                </Suspense>
            </div>
        );
    }
    

动态路由

  • 动态路由:根据后端数据动态生成
function  ListItem(list){
    if(list.length>0){
        return  list.map((item,index)=>{
            return  <Route key={index} path="bashbord" element={LazyC('DashBord')}></Route>
        })
    }
}
  • 路由组件执行流程:到内部页面,需要再执行路由表>redux(项目中讲)
  • 总结:
    • 根据后端数据动态生成
    • 登录获取权限
    • 到内部页面,重新执行路由表(只能执行一次)
      • 由于路由守卫和重定向使用了路由跳转,所以会重新创建组件,所以不应放在根组件,应放到布局组件中
  • 权限:
    • 基础版本:前端:内部和外部页面=>导航守卫 后端:内部和外部接口 (官网)
    • 进阶版本:页面:侧边栏导航、动态路由 (后台管理系统)
    • 终极版本:可以自己设置权限 (后台管理系统)