React(七):Router基本使用、嵌套路由、编程式导航、路由传参、懒加载

一、React-Router的基本使用

1.安装和介绍

安装:

npm install react-router-dom

react-router最主要的API是给我们提供的一些组件:BrowserRouterHashRouter

其中BrowserRouter使用history模式;

import React from "react"
import ReactDOM from "react-dom/client"
import { BrowserRouter } from "react-router-dom"
import App from "./App"

const root = ReactDOM.createRoot(document.querySelector("#root"))

root.render(
  <BrowserRouter>
    <App/>
  </BrowserRouter>
)

HashRouter使用hash模式:

import React from "react"
import ReactDOM from "react-dom/client"
import { HashRouter } from "react-router-dom"
import App from "./App"

const root = ReactDOM.createRoot(document.querySelector("#root"))

root.render(
  <HashRouter>
    <App/>
  </HashRouter>
)

2.路由的配置和跳转

在App中通过使用Routes和Route组件指定路由的出口,path属性指定对应路径,element属性指定要切换的组件实例。

通过Link组件实现路由的跳转,to属性指定切换的路径

import React, { PureComponent } from 'react';
import Home from './pages/Home';
import Search from './pages/Search';
import Detail from './pages/Detail';
import {Routes, Route, Link} from 'react-router-dom';

export class App extends PureComponent {
  render() {
    return (
      <div>
        <div className="header">
          Header<hr />
          <Link to='/home'>点击切换到Home</Link><hr />
          <Link to='/detail'>点击切换到detail</Link><hr />
          <Link to='/search'>点击切换到search</Link><hr />
        </div>
        <div className="content">
          中间的路由内容
          <Routes>
            <Route path='/home' element={<Home />} />
            <Route path='/detail' element={<Detail />} />
            <Route path='/search' element={<Search />} />
          </Routes>
        </div>
        <div className="foorer">Footer</div>
      </div>
    )
  }
}

export default App

在这里插入图片描述

3.Navigate的使用

Navigate用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中

比如我们举个例子,用户来到登录页:
如果没登陆就显示登录按钮;
如果点击登录按钮,就把状态设置为登录,然后就自动跳转到home页。

import React, { PureComponent } from 'react'
import { Navigate } from 'react-router-dom';

export class Login extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      isLogin: false
    }
  }

  login() {
    this.setState({
      isLogin: true
    })
  }
  render() {
    let { isLogin } = this.state;
    return (
      <div>
        <h1>Login</h1>
        {!isLogin ? <button onClick={(() => this.login())}>登录</button> : <Navigate to='/home'/>}
      </div>

    )
  }
}

export default Login

还有就是路由的重定向问题,如果遇到地址只有一个/,那么就导航至home页(或者其实直接写Home组件 <Route path='/' element={<Home />} />也可以的)

  <Routes>
    <Route path='/' element={<Navigate to='/home' />} />
    <Route path='/home' element={<Home />} />
    <Route path='/detail' element={<Detail />} />
    <Route path='/login' element={<Login />} />
  </Routes>

4.如果找不到对应的路由路径?

此时我们可以设置path='*'时(找不到路径时),自动路由跳转到某个组件,给用户提示

  <Routes>
    <Route path='/' element={<Navigate to='/home' />} />
    <Route path='/home' element={<Home />} />
    <Route path='/detail' element={<Detail />} />
    <Route path='/login' element={<Login />} />
    <Route path='*' element={<NotFound />} />
  </Routes>

在这里插入图片描述

二、嵌套路由的用法

在vue中我们需要去配置children这个配置项,但是在react中,不需要噢。

比如我要在Home里面搞个导航栏切换对应的内容:

在这里插入图片描述
那么首先先建三个组件:

在这里插入图片描述

然后来到App,在Home页的这个Route标签中间写嵌套的路由,这里的第一行是一个重定向,如果进入Home页,默认导航至第一个组件Column1

在这里插入图片描述
然后回到Home页,设置跳转的标签和子路由的出口<Outlet>

在这里插入图片描述

当然啊Outlet啊,Route啊,Link啊这些组件别忘了引入。

三、编程式路由导航

React-router给我们提供了一个hook,名字叫useNavigate,调用它可以返回一个函数,我们调用这个函数并把path传给它就可以实现随时通过点击事件进行路由的跳转。

但是既然是hook,那么就只能在函数式组件中使用,如果要在类组件中使用呢?

1.类组件中使用useNavigate

在类组件中想要使用hook并不是不可以,我们可以通过一个高阶组件,给类组件注入这个hook,然后通过props就能调用并传参。

在做高阶组件时,返回的应该是一个函数式组件(如果是类组件不还是用不了吗),然后把useNavigate的返回值(一个函数)注入进去

import { useNavigate } from "react-router-dom";

export default function enhanceUseNavigate(Component) {
    //这里要通过函数式组件注入,因为类组件里不能用噢
    return function(props) {
        let navigate = useNavigate();
        return <Component {...props} navigate={navigate}/>
    }
}

然后另一边使用高阶组件,并且点击按钮时调用传path就行了,这样就可以实现跳转。

export class App extends PureComponent {
  navigateTo(path) {
    //在这里就可以调用注入的跳转函数,传入path进行路由跳转
    this.props.navigate(path);
  }

  render() {
    return (
      <div>
        <div className="header">
          Header<hr />
          <button onClick={() => this.navigateTo('/home')}>点击按钮跳转到Home</button>
          <button onClick={() => this.navigateTo('/detail')}>点击按钮跳转到detail</button>
          <button onClick={() => this.navigateTo('/login')}>点击按钮跳转到登录页</button>
        </div>
        <div className="content">
          <h4>中间的路由内容:</h4>
          <Routes>
            <Route path='/' element={<Navigate to='/home' />} />
            <Route path='/home' element={<Home />} />
            <Route path='/detail' element={<Detail />} />
            <Route path='/login' element={<Login />} />
            <Route path='*' element={<NotFound />} />
          </Routes>
        </div>
        <div className="foorer">Footer</div>
      </div>
    )
  }
}

export default enhanceUseNavigate(App);

2.函数式组件中使用useNavigate

这东西本来就是为函数式组件而生的,所以在这里使用简直是妙蛙种子到了米奇妙妙屋,妙到家了。

function App() {
  let navigate = useNavigate();
  
  function navigateTo(path) {
    navigate(path);
  }

  return (
      <div>
        <div className="header">
          Header<hr />
          <button onClick={() => this.navigateTo('/home')}>点击按钮跳转到Home</button>
          <button onClick={() => this.navigateTo('/detail')}>点击按钮跳转到detail</button>
          <button onClick={() => this.navigateTo('/login')}>点击按钮跳转到登录页</button>
        </div>
        <div className="content">
          <h4>中间的路由内容:</h4>
          <Routes>
            <Route path='/' element={<Navigate to='/home' />} />
            <Route path='/home' element={<Home />} />
            <Route path='/detail' element={<Detail />} />
            <Route path='/login' element={<Login />} />
            <Route path='*' element={<NotFound />} />
          </Routes>
        </div>
        <div className="foorer">Footer</div>
      </div>
    )
}

export default App;

四、路由跳转传参

1.设置好路径的占位符(params)

类似于vue中的params参数
注意,写了占位,如果不传,那么路径就会置空

在这里插入图片描述

通过拼接:参数名可以设置参数的key,这样的话就可以把参数的value通过Link或编程式导航传给Detail组件。

那么参数怎么接呢?

这里要提到另一个hook用来接收参数,useParams,但是呢如果Detail组件是一个类组件,那么我们就要用高阶组件给它注入这个东西:

拿刚才那个高阶组件举例吧,还是同样的方法,把params注入给Detail的props。

import { useNavigate, useParams } from "react-router-dom";

export default function enhanceUseNavigate(Component) {
    //这里要通过函数式组件注入,因为类组件里不能用噢
    return function (props) {
        let navigate = useNavigate();
        let params = useParams();
        let router = { navigate, params };
        return <Component {...props} router={router} />
    }
}

最后来到Detail组件,可以直接读取,参数传过来放到对象里,我们就能去读它的id,或者用它发请求什么的。

import React, { PureComponent } from 'react';
import enhanceUseNavigate from '../utils/enhanceUseNavigate';

export class Detail extends PureComponent {
  render() {
    let { params } = this.props.router;
    console.log(params);//{id: '123'}
    return (
      <div>
        <h1>Detail</h1>
        <h2>收到路由跳转传来的参数:{params.id}</h2>
      </div>
    )
  }
}

export default enhanceUseNavigate(Detail)

2.参数直接拼接到url中(query)

类似vue中的query参数

在这里插入图片描述
直接在跳转的地方拼接url参数,那么怎么接呢?

这里用到另一个hook:useSearchParams

当然在函数式组件中用会比较合适,但是这里我们在类中演示吧,还是用高阶组件,拿之前那个举例:

import { useNavigate, useParams, useSearchParams } from "react-router-dom";

export default function enhanceUseNavigate(Component) {
    //这里要通过函数式组件注入,因为类组件里不能用噢
    return function (props) {
        // 1.导航
        const naviagte = useNavigate()

        // 2.动态路由的参数
        const params = useParams()

        // 3.查询字符串的参数
        const [searchParams] = useSearchParams()
        // console.log(searchParams.get('name'))
        const query = Object.fromEntries(searchParams.entries())
        console.log(query);
        const router = { naviagte, params, query}

        return <Component {...props} router={router} />
    }
}

这里的写法没怎么见过,先记住吧。总之就是把传过来的url参数变成一个对象,里面存着键值对格式的参数。同样我们注入到Login组件中,就可以接到参数了

import React, { PureComponent } from 'react'
import enhanceUseNavigate from '../utils/enhanceUseNavigate';;

export class Login extends PureComponent {
  render() {
    let { query } = this.props.router;
    return (
      <div>
        <h1>Login</h1>
        <h2>拿到query参数!{query.name}-{query.age}</h2>
      </div>
    )
  }
}

export default enhanceUseNavigate(Login)

五、路由的配置文件

目前我们所有的路由都配置在组件中,用标签的形式写出来的,这样会比较乱,那么我们想像vue一样有自己的独立配置,react给我们提供了这样的hook

比如我们要把下面这一堆路由关系配置成一个单独的文件

<div className="content">
  <h4>中间的路由内容:</h4>
   <Routes>
     <Route path='/' element={<Navigate to='/home' />} />
     <Route path='/home' element={<Home />} >
       <Route path='/home' element={<Navigate to='/home/column1' />}></Route>
       <Route path='/home/column1' element={<Column1 />}></Route>
       <Route path='/home/column2' element={<Column2 />}></Route>
       <Route path='/home/column3' element={<Column3 />}></Route>
     </Route>
     <Route path='/detail/:id' element={<Detail />} />
     <Route path='/login' element={<Login />} />
     <Route path='*' element={<NotFound />} />
   </Routes>
 </div>

大概就是这样的:

import Home from '../pages/Home';
import Login from '../pages/Login';
import Detail from '../pages/Detail';
import NotFound from '../pages/NotFound';
import Column1 from '../pages/Column1';
import Column2 from '../pages/Column2';
import Column3 from '../pages/Column3';
import { Navigate } from 'react-router-dom';

let routes = [
    {
        path:'/',
        element: <Navigate to='/home'/>  //重定向
    },
    {
        path:'/home',
        element: <Home/>,
        children: [
            {
                path:'/home',
                element: <Navigate to="/home/column1"/> //重定向
            },
            {
                path:'/home/column1',
                element: <Column1/>
            },
            {
                path:'/home/column2',
                element: <Column2/>
            },
            {
                path:'/home/column3',
                element: <Column3/>
            }
        ]
    },
    {
        path:'/detail/:id',
        element: <Detail/>
    },
    {
        path:'/login',
        element: <Login/>
    },
    {
        path: '*',
        element: <NotFound/>
    }
]

export default routes;

然后在App中需要导入routes,并且使用hook占位:

在这里插入图片描述
ok搞定

六、路由的懒加载

两步
1、换成这个

在这里插入图片描述
2、包个标签

import { Suspense } from 'react';
......
root.render(
  <HashRouter>
    <Suspense fallback={<h3>路由懒加载加载中!!</h3>}>
      <App />
    </Suspense>
  </HashRouter>
);

这里fallback里的东西是加载没出来的时候显示的东西

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Router v6中,嵌套路由使用略有不同。你可以使用`<Route>`组件来定义嵌套路由,并使用`element`属性指定要渲染的组件。下面是一个示例: ```jsx import { Route, Routes } from 'react-router-dom'; import { News } from './News'; import { Message } from './Message'; export const Home = () => { return ( <div> <h3>Home</h3> <div> <ul className="nav nav-tabs"> <li> <MyNavLink to="news">News</MyNavLink> </li> <li> <MyNavLink to="message">Message</MyNavLink> </li> </ul> {/* 注册路由 */} <Routes> <Route path="news" element={<News />} /> <Route path="message" element={<Message />} /> </Routes> </div> </div> ); }; ``` 在上面的代码中,我们使用`<Routes>`组件包裹了多个`<Route>`组件,每个`<Route>`组件定义了一个嵌套路由的路径和要渲染的组件。例如,当路径为"/news"时,会渲染`<News>`组件。这样,当用户访问"/news"时,`<News>`组件就会被渲染在嵌套路由的位置上。 希望这能回答你的问题!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [React Router v6 路由配置,嵌套路由](https://blog.csdn.net/Snow_GX/article/details/123656412)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [react-router-dom v6版本 嵌套路由](https://blog.csdn.net/jzh1359314792/article/details/126526047)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值