React 之Router路由(含5.0与6.0版本)

目录

一、介绍

二、事前准备

2.1 安装路由模块

2.2  相关组件 

三、V5版本路由使用

3.1  声明式导航

3.2  编程式导航

3.3  嵌套路由

3.4  路由传参

3.4.1   动态路由参数(param)

3.4.2 查询字符串(query)

3.4.3  隐式传参(state)

3.5  重定向 与 404

3.6   三种路由的渲染方式【了解】

3.6.1  component= (组件对象或者函数)

3.6.2   render 函数

3.6.3   children(函数或者组件)

3.7  withRouter高阶组件

3.8  自定义导航组件

四、V6版本路由使用

4.1  声明式导航

4.2  编程式导航

4.3  重定向与404

4.3.1  重定向

4.3.2  404  

4.4  传参

4.4.1  query传参

4.4.2   params传参

4.4.3   state传参

​4.5  嵌套路由

 4.6  批量配置路由


一、介绍

现代的前端应用大多数是SPA(单页应用程序),也就是只有一个HTML页面的应用程序。因为它的用户体验更好、对服务器压力更小,所以更受欢迎。为了有效的使用单个页面来管理多页面的功能,前端路由应运而生。

Ø 前端路由功能:让用户从一个视图(组件)导航到另一个视图(组件)

Ø 前端路由是一套映射规则,在React中,是URL路径与组件的对应关系

Ø 使用React路由简单来说,就是配置路径和组件

注意:2021年11月路由依赖包react-router-dom开启v6版本,注意新api的变化

在介绍完v5.0稳定版以后,会在文章后面介绍v6.0版本的改动以及案例演示。 

二、事前准备

2.1 安装路由模块

npm i -S react-router-dom    安装指令

2.2  相关组件 

Ø Router组件:包裹整个应用,一个React应用只需要使用一次

Router: HashRouter和BrowserRouter

​ HashRouter: 使用URL的哈希值实现 (localhost:3000/#/first)

​ BrowserRouter:使用H5的history API实现(localhost3000/first)

Ø Link/NavLink组件:用于指定导航链接(a标签)

​ 最终Link会编译成a标签,而to属性会被编译成 a标签的href属性

Ø Route组件:指定路由展示组件相关信息(组件渲染)

path属性:路由规则,这里需要跟Link组件里面to属性的值一致

component属性:展示的组件

三、V5版本路由使用

3.1  声明式导航

使用Link或NavLink组件完成声明式导航的定义

代码展示:

import React, { Component } from 'react';
// 引入相关组件
import { Link,Route,Switch,NavLink } from 'react-router-dom'
// 引入类组件
import Home from './pages/Home';
import User from './pages/User';

class App extends Component {
    render() {
        return (
            <>
            {/* 声明式导航 */}
            
               < NavLink to={"/home"} >home页面</NavLink>
               < NavLink to={"/user"}>user页面</NavLink>

               <Switch>
               <Route path={"/home"} component = { Home }></Route>
               <Route path={"/user"} component = { User }></Route>
               </Switch>
            </>
        );
    }
}

export default App;

运行结果:

3.2  编程式导航

通过与react-router-dom中withRouter与history对象中的push/replace/go等方法搭配使用实现编程式导航功能。

这里需要注意,引入whitRouter,用于解决this.props.history 拿不到值的问题。

import React, { Component } from 'react';
// 引入相关组件
import { Link,Route,Switch,NavLink } from 'react-router-dom'
// 引入类组件
import Home from './pages/Home';
import User from './pages/User';
// 引入withRouter来解决 this.props.history 拿不到值的问题
import { withRouter } from 'react-router-dom'
@withRouter
class App extends Component {
    homeHander = () =>{
       console.log(this.props.history); 
       this.props.history.push("/home")
    }
    userHander = () =>{
        console.log(this.props.history); 
        this.props.history.push("/user")
     }
    render() {
        return (
            <>
            {/* 编程式导航 */}
               <a onClick={this.homeHander}>home界面</a>
               <a onClick={this.userHander}>user界面</a>
               <Switch>
               <Route path={"/home"} component = { Home }></Route>
               <Route path={"/user"} component = { User }></Route>
               </Switch>
            </>
        );
    }
}

export default App;

3.3  嵌套路由

在有一些功能中,往往请求地址的前缀是相同的,不同的只是后面一部份,此时就可以使用多级路由(路由嵌套)来实现此路由的定义实现。

例如,路由规则如下

admin/index
​
admin/user

它们路由前缀的admin是相同的,不同的只是后面一部份。

获取前缀,供后续地址做路由拼接

let prefix = this.props.match.path;

3.4  路由传参

路由参数:在Route定义渲染组件时给定动态绑定的参数。

React路由传参方式有三种:

Ø 动态路由参数(param)

​ 以“/detail/:id”形式传递的数据

​ 在落地组件中通过this.props.match.params得到

Ø 查询字符串(query)

​ 通过地址栏中的 home?key=value&key=value传递

​ 在落地组件中通过this.props.location.search得到

Ø 隐式传参(state),通过地址栏是观察不到的

​ 通过路由对象中的state属性进行数据传递

​ 在落地组件中通过this.props.location.state得

3.4.1   动态路由参数(param)

通过this.props.match.params拿值

运行结果:

3.4.2 查询字符串(query)

通过 this.props.location.search 拿值

运行结果: 

3.4.3  隐式传参(state)

这里注意,传过去的参数刷新会消失

通过this.props.location.state拿state的值

通过this.props.history.location.params拿params的值

运行结果: 

3.5  重定向 与 404

# 重定向 from从哪里来 to重定向到何处去
<Redirect from="/home" to="/" />

# 404设置
<Route component={Notfound} />

这里的Notfound需要引入对应的404类组件

3.6   三种路由的渲染方式【了解】

3.6.1  component= (组件对象或者函数)

<Route path="/home" component={Home} />

<Route path="/home" component={()=><Home />} />

3.6.2   render 函数

<Route path="/home" render={props=><Home />} />

3.6.3   children(函数或者组件)

// 全匹配
<Route path="/about" children={props=>{
    return <div>children渲染</div>
}} />

// 精确匹配
<Route path="/about" children={<About />} />

3.6.4  3种渲染区别总结

  • component可以使用组件类渲染或内联式方式渲染,render只能使用函数,children使用函数或直接使用组件对象

  • component内联式渲染方式在每次匹配路由成功后都将创建一个新组件,而后两者不会,所以用内联式方式建议使用后两者,内联方式渲染组件,推荐用render

  • 当children的值是一个函数时,无论当前地址和path路径匹不匹配,都将会执行children对应的函数,当children的值为一个组件时,当前地址和path不匹配时,路由组件不渲染

  • children函数方式渲染,会在形参中接受到一个对象,对象中match属性如果当前地址匹配成功返回对象,否则null

3.7  withRouter高阶组件

作用:把不是通过路由切换过来的组件中,将react-router 的 history、location、match 三个对象传入props对象上

默认情况下必须是经过路由匹配渲染的组件才存在this.props,才拥有路由参数,才能使用编程式导航的写法,执行this.props.history.push('/uri')跳转到对应路由的页面,然而不是所有组件都直接与路由相连的,当这些组件需要路由参数时,使用withRouter就可以给此组件传入路由参数,此时就可以使用this.props

import {
    useLocation,
    useNavigate, 
    useParams
  } from "react-router-dom";
//   useNavigate  用来跳转用的  函数组件使用  useLocation接收参数用 useParams接收参数
  export function withRouter(Component) {
    function ComponentWithRouterProp(props) {
      let location = useLocation();
      let navigate = useNavigate();
      let params = useParams();
      return (
        <Component
          {...props}
          router={{ location, navigate, params }}
        />
      );
    }
  
    return ComponentWithRouterProp;
  }

3.8  自定义导航组件

为何需要自定义导航?

因为在项目中往往不是所有的声明式导航都是需要a标签完成,有时候可能需要别的标签,此时如果在需要的地方去写编程式导航就会有代码重复可能性,就在对于公共代码进行提取。

思路:

Ø 定义一个普通组件可以是类组件也可以是函数式组件MyLink

Ø 父组件能向子组件传值 props

Ø 不管路由规则是否匹配都要显示组件 Route children渲染方式(函数式)

Ø 注意点:react中组件是大写字母开头 html也是组件

import React, { Component } from 'react';
// 引入相关组件
import { Link,Route,Switch,NavLink } from 'react-router-dom'
// 引入函数组件
import Home from './pages/Home';
import User from './pages/User';
// 引入自定义导航组件
import Mylink from './pages/Mylink';
class App extends Component {
    render() {
        return (
            <>
            {/* 传参 */}
            
               < NavLink to="/home" >home页面</NavLink>
               < NavLink to="/user">user页面</NavLink>
               {/* 引入自定义导航组件 */}
               <Mylink to="/home" tag = 'p'>首页</Mylink>
               <Mylink to="/user"tag = 'p'>用户页</Mylink>

               <Switch>
               <Route path="/user"  component = { Home }></Route>
               <Route path="/user" component = { User }></Route>
               </Switch>
            </>
        );
    }
}

export default App;

   自定义路由组件  公共组件

import React from 'react';
import { Route , withRouter } from 'react-router-dom'

const Mylink = (props) => {
    const handerClick = () => {
        props.history.push(props.to)
    }
    const Tag = props.tag
    const to = props.to

    return (
      // match 使用函数组件 类组件match获取不到最新匹配的值
             <Route path={to} children={({match})=>{
               console.log('match',match);
              if(match){
                   return <Tag style={{color:'red'}} onClick={ handerClick }
                  >{ props.children }</Tag>
              }
              return <Tag  onClick={handerClick}
                  >{ props.children }</Tag>
            }} />
    );
}

export default withRouter(Mylink);

运行结果:

四、V6版本路由使用

4.1  声明式导航

三个改动:

  1. swicth替换为 Routes

  2. comopnent替换为 element

  3. element里以前是直接放User 现在是<User/>

import React, { Component } from 'react';
import { Route, Routes, Link, useNavigate } from 'react-router-dom'
import User from './pages/User';
import Home from './pages/Home';
class App extends Component {
    render() {
        return (
            <>
                {/* swicth替换为 Routes */}
                <Routes>
                    {/* comopnent替换为 element */}
                    <Route path='/home' element={<Home />}></Route>
                    {/* 以前是直接放User 现在是<User/> */}
                    <Route path='/user' element={<User />}></Route>
                </Routes>
                <Link to={'/home'}>首页</Link>
                <Link to={'/user'}>用户</Link>
            </>
        );
    }
}

export default App;

4.2  编程式导航

通过this.props.router.navigate进行路径更改

需要注意的是V6版本中,删除了withRouter,所以需要自己封装,并引入

WithRouter代码如下:

import {
    useLocation,
    useNavigate, 
    useParams
  } from "react-router-dom";
//   useNavigate  用来跳转用的  函数组件使用  useLocation接收参数用 useParams接收参数
  export function withRouter(Component) {
    function ComponentWithRouterProp(props) {
      let location = useLocation();
      let navigate = useNavigate();
      let params = useParams();
      return (
        <Component
          {...props}
          router={{ location, navigate, params }}
        />
      );
    }
  
    return ComponentWithRouterProp;
  }

代码展示: 

import React, { Component } from 'react';
import { Route, Routes, Link, useNavigate } from 'react-router-dom'
import User from './pages/User';
import Home from './pages/Home';
// 需要自己封装 V6版本删除了withRouter
import  {withRouter}  from './pages/WithRouter';

class App extends Component {
    hander = ()=>{
        
        console.log(this.props);

        this.props.router.navigate('/home')
    }
    handers = ()=>{
        console.log(this.props);
        this.props.router.navigate('/user')
    }
    render() {
        return (
            <>
                {/* swicth替换为 Routes */}
                <Routes>
                    {/* comopnent替换为 element */}
                    <Route path='/home' element={<Home />}></Route>
                    {/* 以前是直接放User 现在是<User/> */}
                    <Route path='/user' element={<User />}></Route>
                    
                </Routes>

                <Link to={'/home'}>首页</Link>
                <Link to={'/user'}>用户</Link>
                {/* 编程式导航 */}
                <button onClick={this.hander}>首页</button>
                <button onClick={this.handers}>用户</button>

            </>
        );
    }
}

export default withRouter(App);

运行结果:

4.3  重定向与404

4.3.1  重定向

先引入navigate

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

使用

<Route index element={ <Navigate to="/home "/>}/>

4.3.2  404  

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

4.4  传参

4.4.1  query传参

this.props.router.location.search 接收参数

this.props.router.navigate('/home?name=xzl')

4.4.2   params传参

this.props.router.params  接收参数

this.props.router.navigate('/user/12345')   传参
<Route path='/user/:id' element={<User />}></Route>   路由更改

4.4.3   state传参

注意:V6中state传参只能用于函数组件,类组件不可用

先引入 

import { useLocation } from 'react-router-dom'

再赋值

var localtion = useLocation()

最后通过 localtion.state 接收参数。

4.5  嵌套路由

方法一:

<Routes>
{/* 注意带*号表示下面有路由匹配 */}
    <Route path='/home/*' element={<Home />}>
       {/* 二级路由不带  /   */}
        <Route path='Footer' element={<Footer />}></Route>
        <Route path='Header' element={<Header />}></Route>
            </Route>
     <Route path='/user' element={<User />}></Route>
 </Routes>

注意这里需要在二级路由页面有类似于vue路由占位符一样的东西。

<Outlet />    占位符

方法二:

 4.6  批量配置路由

import React from 'react'
import { useRoutes } from 'react-router-dom'
import Home from './pages/Home'
import User from './pages/User'
import NotFind from './pages/NotFind'
import MyHeader from './pages/MyHeader'
import MyFooter from './pages/MyFooter'

export default function App() {
    //useRoutes   //use开头的函数 统称hooks 函数组件专用  v6常用编程了函数组件
    var ele = useRoutes([
        { 
            path:'/home',
            element: <Home />,
            children:[
                {path:'myheader',element: <MyHeader /> },
                {path:'myfooter',element: <MyFooter /> },
            ]
        },
        { path:'/user',element: <User />},
        { path:'*',element: <NotFind />},
    ])
  return (
    <div>
        <h3>useRoutes案例</h3>
        { ele }
    </div>
  )
}

  • 23
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
React Router 提供了一些钩子函数来拦截路由,这样我们就可以在路由跳转之前或之后进行相关的操作。下面是一个简单的路由拦截示例: ```javascript import React from 'react'; import { BrowserRouter as Router, Route, Link, Redirect } from 'react-router-dom'; const isAuthenticated = true; const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={(props) => ( isAuthenticated === true ? <Component {...props} /> : <Redirect to='/login' /> )} /> ); const LoginPage = () => ( <div> <h1>Login Page</h1> </div> ); const HomePage = () => ( <div> <h1>Home Page</h1> </div> ); const App = () => ( <Router> <div> <ul> <li><Link to='/'>Home</Link></li> <li><Link to='/login'>Login</Link></li> </ul> <hr /> <PrivateRoute exact path='/' component={HomePage} /> <Route path='/login' component={LoginPage} /> </div> </Router> ); export default App; ``` 在上面的代码中,我们定义了一个 `PrivateRoute` 组件来实现路由拦截。如果用户已经认证,则展示 `component` 组件,否则重定向到登录页面。 另外,我们还定义了两个页面组件:`HomePage` 和 `LoginPage`。在 `App` 组件中,我们使用 `PrivateRoute` 组件来保护 `HomePage` 组件,这样只有已经认证的用户才能访问该页面。 如果你想在路由跳转之前进行相关的操作,可以使用 `react-router` 提供的 `Prompt` 组件。下面是一个简单的示例: ```javascript import React, { useState } from 'react'; import { BrowserRouter as Router, Route, Link, Prompt } from 'react-router-dom'; const App = () => { const [isBlocking, setIsBlocking] = useState(false); const handleChange = (event) => { setIsBlocking(event.target.value.length > 0); }; return ( <Router> <div> <ul> <li><Link to='/'>Home</Link></li> <li><Link to='/about'>About</Link></li> </ul> <hr /> <Prompt when={isBlocking} message={location => `Are you sure you want to go to ${location.pathname}?`} /> <Route exact path='/' render={() => ( <div> <h1>Home Page</h1> <input type='text' onChange={handleChange} /> </div> )} /> <Route path='/about' render={() => ( <div> <h1>About Page</h1> </div> )} /> </div> </Router> ); }; export default App; ``` 在上面的代码中,我们使用 `Prompt` 组件来拦截路由,在用户输入内容时,如果尚未保存,就弹出提示框。提示框的内容可以通过 `message` 属性来设置。如果用户选择离开当前页面,则路由会跳转到目标页面。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大聪明码农徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值