React-router-dom基础使用教程

React路由

1、SPA应用

  • 单页面多组件应用
  • 整个应用只有一个完整的页面
  • 点击页面中的链接不会刷新页面,只会做页面的局部更新
  • 数据都需要通过ajax请求获取,并在前端异步展现

2、路由理解

2.1、什么是路由

  • 路由就是一组映射关系,key就是路径,value对应的就是一个一个函数或者组件

2.2、路由分类

  • 路由分为前端路由和后端路由
    • 后端路由对应的就是请求的接口地址
    • 前端路由就是对应的导航栏的地址,一个地址对应一个页面或者组件
      • 前端路由又分为两种:Hash路由、history路由
        • Hash路由:会在地址栏后面拼接#/xxx/xxx,兼容性最好,但是地址栏不美观
        • history路由:由H5新推出的windows上自带的API,地址栏干净,但是兼容性没有上面的好

3、react-router-dom

  • react-router推出了三款根据不同平台的路由,这里主要演示web,any东西太杂,不容易理解
    • web
    • native
    • any,上面都可以用的

3.1、安装

// 这里安装的 5 的版本

npm i react-router-dom@5

3.2、基本使用

  • BrowserRouter组件:应该放到index.js<App />外侧,这样App中的所有路由皆是同一个映射关系一个BrowserRouter标签内的Link、Route为同一组Map映射,两组不同的映射之间无法关联,所以一般会在<App />最外侧放置一个即可
  • HashRouter组件:与上面用法一直,只不过是Hash路由的方式
  • Link组件:组件中的to属性绑定一个地址(前面不能加.)用于定义映射关系中的key属性,渲染到页面上的时候,会渲染为a标签,并且to属性的值会被转为a标签上的href属性
  • Route组件:组件中的path属性对应上面定义的keycomponent属性对应一个组件,即value
  • 还有其他组件,可自行去官网查看…

下面使用一个案例来演示使用

BrowserRouter效果

在这里插入图片描述

HashRouter效果

在这里插入图片描述

index.js
import React from "react";
import ReactDOM from "react-dom/client";
// 引入 BrowserRouter: history路由    HashRouter:hash路由 组件
import { BrowserRouter, HashRouter } from "react-router-dom";
import "./index.css";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // 包裹在最外侧
  <BrowserRouter>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </BrowserRouter>
);
App.jsx
import React, { Component } from "react";
import { Link, Route} from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import "./App.css"

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          <Link to="/home" className="link">Home</Link>
          <Link to="/about" className="link">About</Link>
        </div>
        <div className="rightContent">
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
        </div>
      </div>
    </div>;
  }
}
App.css
.app {
  margin-left: 20vw;
}
.app .main {
  display: flex;
  column-gap: 30px;
}

.app .leftToolBar {
  display: flex;
  flex-direction: column;
}

.app .leftToolBar .link {
  padding: 6px 20px;
  border: 1px solid #000;
  border-radius: 4px;
}

.app .leftToolBar .link:focus {
  background-color: gray;
  color: #fff;
}
About&Home

在这里插入图片描述

4、高级使用

4.1、一般组件与路由组件

  • 上面的Home、About两个组件就是路由组件,咱们上面演示的组件Search、List就是一般组件
  • 区别:
    1. 写法不同
      1. 一般组件:<Demo/>
      2. 路由组件:<Route path="/demo" component={Demo}/>
    2. 存放位置不同:
      1. 一般组件:src/components目录下
      2. 路由组件:src/pages目录下
    3. 接收到的props不同
      1. 一般组件:写组件标签时传递了什么,就能收到什么
      2. 路由组件:接收到三个固定的属性
        1. history:
          1. action: "PUSH"
          2. block: ƒ block(prompt)
          3. createHref: ƒ createHref(location)
          4. *go: ƒ go(n)
          5. ==*==goBack: ƒ goBack()
          6. *goForward: ƒ goForward()
          7. length: 6
          8. listen: ƒ listen(listener)
          9. location: {pathname: '/home', search: '', hash: '', state: undefined, key: '1ahhdt'}
          10. *push: ƒ push(path, state)
          11. ==*==replace: ƒ replace(path, state)
        2. location:
          1. hash: ""
          2. key: "1ahhdt"
          3. *pathname: "/home"
          4. *search: ""
          5. *state: undefined
        3. match:
          1. isExact: true
          2. *params: {}
          3. ==*==path: "/home"
          4. ==*==url: "/home"

4.2、NavLink路由激活样式

  • NavLink:Link组件不同的是,如果当前路由和标签上的to属性值一样的话,就会标签上添加一个默认名为active的类名,用于给激活标签添加自定义样式
  • 如果想要修改默认激活样式名,在标签上添加属性activeClassName="xxxx"即可修改
  • 上面咱们是使用:forcus添加样式的,如果用户点了其他地方,那么样式就会丢失,下面咱们优化一下样式,以及把Link组件换为NavLink组件
App.css
.app {
  margin-left: 20vw;
}
.app .main {
  display: flex;
  column-gap: 30px;
}

.app .leftToolBar {
  display: flex;
  flex-direction: column;
}

.app .leftToolBar .link {
  padding: 6px 20px;
    border-radius: 4px;
  border: 1px solid #000;
}

/* 激活样式 */
.app .leftToolBar .activeToolBar {
  background-color: gray;
  color: #fff;
}
App.jsx
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          {/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
          <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink>
          <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink>
        </div>
        <div className="rightContent">
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
        </div>
      </div>
    </div>
  }
}

4.3、优化NavLink

  • 上面NavLink标签上,一般activeClassName、className属性基本都是一样的,正常项目都会有很多页面,很多路由,写这么多难维护,所以咱们可以把公共的提取出来,封装成一个组件
  • 使用this.props.children即可获取父组件在子组件中传入的所有子元素!!
MyNavLink组件
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          {/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
          {/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
          {/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
          <MyNavLink to="/home">Home</MyNavLink>
          {/* <MyNavLink to="/about">About</MyNavLink> */}

          {/* 或者如下写法传入标签体 */}
          <MyNavLink to="/about" children="About" />

        </div>
        <div className="rightContent">
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
        </div>
      </div>
    </div>
  }
}
App组件
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          {/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
          {/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
          {/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
          <MyNavLink to="/home">Home</MyNavLink>
          {/* <MyNavLink to="/about">About</MyNavLink> */}

          {/* 或者如下写法传入标签体 直接在当做属性写 */}
          <MyNavLink to="/about" children="About" />

        </div>
        <div className="rightContent">
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
        </div>
      </div>
    </div>
  }
}

4.4、Switch组件

  • 这里我们再写一个测试的路由组件,并且配置和/about一样的key,不一样的value路由组件
  • 结果是两个组件都会被渲染出来,这就证明了,匹配路由的时候,是从上往下一个一个匹配,如果匹配成功,依旧会往下继续匹配
  • 那么,我们可以在外面套一层Switch组件,这样在匹配到一个的时候,不会继续往下匹配了,这样可以提高性能!
没有Switch组件时
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import "./App.css"
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          {/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
          {/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
          {/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
          <MyNavLink to="/home">Home</MyNavLink>
          {/* <MyNavLink to="/about">About</MyNavLink> */}

          {/* 或者如下写法传入标签体 */}
          <MyNavLink to="/about" children="About" />

        </div>
        <div className="rightContent">
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/about" component={Test} />
        </div>
      </div>
    </div>
  }
}

在这里插入图片描述

Switch组件时
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import "./App.css"
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          {/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
          {/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
          {/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
          <MyNavLink to="/home">Home</MyNavLink>
          {/* <MyNavLink to="/about">About</MyNavLink> */}

          {/* 或者如下写法传入标签体 */}
          <MyNavLink to="/about" children="About" />

        </div>
        <div className="rightContent">
          <Switch>
            <Route path="/home" component={Home} />
            <Route path="/about" component={About} />
            <Route path="/about" component={Test} />
          </Switch>
          
        </div>
      </div>
    </div>
  }
}

在这里插入图片描述

4.5、样式丢失问题

  • 想要实现效果,我们需要把app.css移动到public/css/App.css这里,然后在public/index.html里面使用link引入改样式,<link rel="stylesheet" href="./css/App.css" />,最后把App.jsx里面引入App.css的样式注释掉即可
  • 假设我们要给原来的key前面添加一个/test,这样路由地址就变为了/test/home

在这里插入图片描述

App.jsx
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          <MyNavLink to="/test/home">Home</MyNavLink>
          {/* 或者如下写法传入标签体 */}
          <MyNavLink to="/test/about" children="About" />

        </div>
        <div className="rightContent">
          <Switch>
            <Route path="/test/home" component={Home} />
            <Route path="/test/about" component={About} />
          </Switch>
          
        </div>
      </div>
    </div>
  }
}
  • 然后点击路由,可以发现没有什么问题,地址栏也会改变,但是当我们点完路由点击浏览器左上角刷新时,就会发现样式丢失了

在这里插入图片描述

  • 这时候咱们点开控制台的网络,然后查看App.css请求,可以发现是200,但是响应结果并不是对应的css,而是index.html
  • 这时候再看一下这个请求的请求地址http://localhost:3000/test/css/App.css,就会发现地址中多了一个/test,去掉就没问题了
  • 原因:
    • 当你访问了一个不存在的地址时,脚手架就会自动返回public目录中的index.html
    • http://localhost:3000内置服务器 就相当于public目录,当路由出现多级路径,并且刷新后,样式就会丢失了
    • 咱们在index.html中的href属性是使用相对路径引入的
  • 修改方法(三种)
    1. href地址中前面的.去掉,改为href="/css/App.css"即可
    2. 把前面的.替换为%PUBLIC_URL%,改为href="%PUBLIC_URL%/css/App.css"即可
    3. 使用HashRouter即可,在index.js中,将BrowserRouter 改为 HashRouter即可,因为==#后面的地址不作为请求地址识别==

4.6、精准匹配与模糊匹配

  • 默认是模糊匹配:输入的路径必须包含匹配的路径,并且顺序必须一致
  • 通过在Route标签上添加exact属性,开启严格匹配,即输入路径必须和匹配路径完全一致
代码
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import MyNavLink from "./components/MyNavLink";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          <MyNavLink to="/home/a/b">Home</MyNavLink>
          <MyNavLink to="/a/about/b" children="About" />
          <MyNavLink to="/a/b/test" children="Test" />

        </div>
        <div className="rightContent">
          <Switch>
            {/* 默认是模糊匹配,只要/home/a/b的第一个和path中的第一个相同,那么则可以匹配成功 */}
            <Route path="/home" component={Home} />
            {/* /a/about/b 的第一个为 a,但是path中的地址第一个为about,不符合,那么就不看后面了,直接匹匹配不到*/}
            <Route path="/about" component={About} />
            {/* 开启严格匹配 由于上面to属性的值和path一致,那么匹配成功*/}
            <Route exact path="/a/b/test" component={About} />
          </Switch>
          
        </div>
      </div>
    </div>
  }
}
效果

在这里插入图片描述

4.7、Redirect重定向组件

  • 我们刚打开页面http://localhost:3000/的时候,什么也不展示,这是因为地址栏斜杠后面没有东西,获取到的是""空串,路由中并没有空串对应的组件,所以什么也不展示
  • 那么我们可以使用Redirect组件,使用to属性指定,当所有路由都没匹配到的时候,就会走这里前往默认的路由
App
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

export default class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <div className="main">
        <div className="leftToolBar">
          <MyNavLink to="/home">Home</MyNavLink>
          <MyNavLink to="/about" children="About" />

        </div>
        <div className="rightContent">
          <Switch>
            <Route path="/home" component={Home} />
            <Route path="/about" component={About} />
            {/* 如果上面路由都匹配不到,那么走下面的路由 */}
            <Redirect to="/home" />
          </Switch>
          
        </div>
      </div>
    </div>
  }
}
效果

在这里插入图片描述

5、嵌套路由

  • 假设我们About组件中,也有一部分内容可以跟随路由跳转而变换,那么我们就要先成功匹配到About路由,再成功匹配到About路由下的子路由
  • 注意:外层路由一定不能开启严格模式,否则嵌套路由将会失效
  • 下面,我使用一个案例,来给大家演示一下用法

效果

在这里插入图片描述

项目结构

在这里插入图片描述

About.jsx

import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

import './about.css'

export default class About extends Component {
  render() {
    return (
      <div className='about'>
        <h2>我是About组件</h2>

        <div className="card">
          <div className="card-item">
            {/* 注意:这里要/about/news,而不是直接/news,这样才能先匹配到 about 路由,再匹配news路由 */}
            <MyNavLink to="/about/news">News</MyNavLink>
          </div>

          <div className="card-item">
            <MyNavLink to="/about/message">Message</MyNavLink>
          </div>
        </div>

        <div className="content">
          {/* 这里需要去定义路由对应组件,否则就会去 App.jsx 那里定义的找,找不到则会走兜底逻辑 /home */}
          <Switch>
            <Route path="/about/news" component={News} />
            <Route path="/about/message" component={Message} />
            {/* 记得这里也给个默认路由 */}
            <Redirect to="/about/news" />
          </Switch>
        </div>
      </div>
    )
  }
}

about.css

.about .card{
  display: flex;
  gap: 20px;
}

.about .card .card-item .link{
  display: block;
  border: 1px solid #000;
  padding: 8px 10px;
  border-radius: 5px;
}

.activeToolBar {
  background-color: #ce801a;
  color: #fff;
}

news.jsx

import React, { Component } from 'react'

export default class News extends Component {
  render() {
    return (
      <div>News</div>
    )
  }
}

message.jsx

import React, { Component } from 'react'

export default class Message extends Component {
  render() {
    return (
      <div>Message</div>
    )
  }
}

6、路由传参

  • 假设我们跳转页面的时候,要把当前页面的数据带到下一个页面使用,就需要实现路由传参了
  • 传参方式共有如下三种,有利有弊,自行选择即可

6.1、params传参

  • 路由链接(携带参数):<MyNavLink to="/about/news/张三/18">News</MyNavLink>
  • 注册路由(声明接收):<Route path="/about/news/:name/:age" component={News} />
  • 接收参数:this.props.match.params
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

import './about.css'

export default class About extends Component {
  render() {
    return (
      <div className='about'>
        <h2>我是About组件</h2>

        <div className="card">
          <div className="card-item">
            {/* 在路由地址中 使用 /张三/18 携带参数 */}
            <MyNavLink to="/about/news/张三/18">News</MyNavLink>
          </div>

          <div className="card-item">
            <MyNavLink to="/about/message/李四/20">Message</MyNavLink>
          </div> 
        </div>

        <div className="content">
          <Switch>
            {/* 注意:使用:xxxx 声明接收 */}
            <Route path="/about/news/:name/:age" component={News} />
            <Route path="/about/message/:name/:age" component={Message} />
            {/* 记得这里也给个默认路由 */}
            <Redirect to="/about/news" />
          </Switch>
        </div>
      </div>
    )
  }
}
News.jsx
import React, { Component } from 'react'

export default class News extends Component {
  render() {
    console.log(this.props);
    
    return (
      <div>
        <h1>News</h1>
        <h2>姓名:{this.props.match.params.name}</h2>
        <h2>年龄:{this.props.match.params.age}</h2>
      </div>
    )
  }
}
Message.jsx
import React, { Component } from 'react'

export default class Message extends Component {
  render() {
    console.log(this.props);

    return (
      <div>
        <h1>Message</h1>
        <h2>姓名:{this.props.match.params.name}</h2>
        <h2>年龄:{this.props.match.params.age}</h2>
      </div>
    )
  }
}
效果

在这里插入图片描述

6.2、search传参

  • 路由链接(携带参数):<MyNavLink *to***=**"/about/news?name=张三&age=18">News</MyNavLink>
  • 注册路由(声明接收):无需声明
  • 接收参数:this.props.location.search
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

import './about.css'

export default class About extends Component {
  render() {
    return (
      <div className='about'>
        <h2>我是About组件</h2>

        <div className="card">
          <div className="card-item">
            {/* 在路由地址中 使用 /?key=value&key2=value2 携带参数 */}
            <MyNavLink to="/about/news?name=张三&age=18">News</MyNavLink>
          </div>

          <div className="card-item">
            <MyNavLink to="/about/message?name=李四&age=20">Message</MyNavLink>
          </div> 
        </div>

        <div className="content">
          <Switch>
            <Route path="/about/news" component={News} />
            <Route path="/about/message" component={Message} />
            {/* 这里如果配置默认路由,组件内将会获取不到页面传参 */}
            {/* <Redirect to="/about/news" /> */}
          </Switch>
        </div>
      </div>
    )
  }
}
News.jsx
import React, { Component } from 'react'

function getQueryParams(searchUrl) {
  const queryParams = new URLSearchParams(searchUrl);
  const paramsObj = {};
  for (const [key, value] of queryParams.entries()) {
    paramsObj[key] = value;
  }
  return paramsObj;
}

export default class News extends Component {

  state = {
    urlParams: {},
  }

  componentDidMount() {
    const params = getQueryParams(this.props.location.search)

    this.setState({ urlParams: params })
  }

  render() {
    const { name, age } = this.state.urlParams;
    return (
      <div>
        <h1>News</h1>
        <h2>姓名:{name}</h2>
        <h2>年龄:{age}</h2>
      </div>
    )
  }
}
Message.jsx
import React, { Component } from 'react'

function getQueryParams(searchUrl) {
  const queryParams = new URLSearchParams(searchUrl);
  const paramsObj = {};
  for (const [key, value] of queryParams.entries()) {
    paramsObj[key] = value;
  }
  return paramsObj;
}

export default class Message extends Component {

  state = {
    urlParams: {},
  }

  componentDidMount() {
    const params = getQueryParams(this.props.location.search)

    this.setState({ urlParams: params })
  }


  render() {
    const { name, age } = this.state.urlParams;
    return (
      <div>
        <h1>Message</h1>
        <h2>姓名:{name}</h2>
        <h2>年龄:{age}</h2>
      </div>
    )
  }
}
效果

在这里插入图片描述

6.3、state传参

  • 路由链接(携带参数):<MyNavLink to={ {pathname: '/about/news', state: {name: '张三', age: 18}}}>News</MyNavLink>
  • 注册路由(声明接收):无需声明
  • 接收参数:this.props.location.state
  • 注意:
    • 如果有默认路由,那么要处理一下参数接收为null的问题
    • 虽然地址栏上没有参数,但是刷新页面依旧会保留参数,因为他借助的H5 的 history API,但是当开无痕或者清除浏览器缓存后,则会丢失参数
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

import './about.css'

export default class About extends Component {
  render() {
    return (
      <div className='about'>
        <h2>我是About组件</h2>

        <div className="card">
          <div className="card-item">
            {/* 在路由地址中 传入对象形式,{pathname: '路由地址', state: {参数对象}} */}
            <MyNavLink to={ {pathname: '/about/news', state: {name: '张三', age: 18}}}>News</MyNavLink>
          </div>

          <div className="card-item">
            <MyNavLink to={{pathname: '/about/message', state: {name: '李四', age: 20}}}>Message</MyNavLink>
          </div> 
        </div>

        <div className="content">
          <Switch>
            <Route path="/about/news" component={News} />
            <Route path="/about/message" component={Message} />
            {/* 注意:如果这里给默认路由了,那么组件内 结构 this.props.location.state 将会报错, 因为 this.props.location.state 为 null */}
            {/* <Redirect to="/about/news" /> */}
          </Switch>
        </div>
      </div>
    )
  }
}
News.jsx
import React, { Component } from 'react'

export default class News extends Component {

  render() {
    const { name, age } = this.props.location.state
    return (
      <div>
        <h1>News</h1>
        <h2>姓名:{name}</h2>
        <h2>年龄:{age}</h2>
      </div>
    )
  }
}
Message.jsx
import React, { Component } from 'react'


export default class Message extends Component {

  render() {
    const { name, age } = this.props.location.state

    return (
      <div>
        <h1>Message</h1>
        <h2>姓名:{name}</h2>
        <h2>年龄:{age}</h2>
      </div>
    )
  }
}
效果

在这里插入图片描述

7、push、replace、goBack、goForward、go等方法

  • 导航路由链其实就是一个堆栈的操作,当我们从一个地址,通过push方法跳入到另一个地址中,就会往堆栈中添加一条记录
  • 我们上面写的,默认都为push的操作,下面我们演示其他一些操作堆栈记录的方法

7.1、push

  • 点击Link标签跳转默认为push路由操作
  • 向堆栈中添加一条记录
代码
<MyNavLink to="/home">Home</MyNavLink>
效果

在这里插入图片描述

7.2、replace

  • 如果在Link组件上添加replace属性,那么则会变为替换操作
  • 会将当前所在记录替换为新地址
代码
<MyNavLink replace to="/about" children="About" />
效果

在这里插入图片描述

7.3、goBack

  • 路由往后退一格,回到上一个页面,并不会删除任何路由
  • 没有对应组件配置,只能使用下方编程式路由跳转

在这里插入图片描述

7.4、goForward

  • 路由往前进一格,前进到下一个页面,并不会删除任何路由
  • 没有对应组件配置,只能使用下方编程式路由跳转

在这里插入图片描述

7.5、go

  • 该方法提供一个参数,如果为正数,则前进参数的步数;如果为负数,则后退参数的步数
  • 没有对应组件配置,只能使用下方[编程式路由跳转](

在这里插入图片描述

在这里插入图片描述

8、编程式路由跳转

  • 上面我们演示了组件标签进行跳转,但是如果我想点击按钮后,打印一句话,然后再进行跳转,就不行了
  • react-router-dom提供了一套API用于操控路由跳转
  • 上面我们提取出来了this.props中默认有的几个history、loaction、match等属性,react-router-dom将提供给我们的API放入了history对象中
  • 有了history对象中的方法,我们就可以在自身的方法中编写任意逻辑,在任意时刻进行路由跳转

8.1、push

<button onClick={() => this.props.history.push('/about/news', {name: '张三', age: 18})}>push跳转到news</button>

8.2、replace

<button onClick={() => this.props.history.replace('/about/message', {name: '李四', age: 20})}>replace跳转到Message</button>

8.3、goBack

<button onClick={() => this.props.history.goBack()}>goBack回退</button>

8.4、goForward

<button onClick={() => this.props.history.goForward()}>goForward前进</button>

8.5、go

<button onClick={() => this.props.history.go(-1)}>go(-1)后退1步</button>
<button onClick={() => this.props.history.go(1)}>go(1)前进1步</button>

8.6、统一效果演示

在这里插入图片描述

9、withRouter

  • withRouter是用来解决一般组件的props中没有history对象操控路由的问题
  • 当我们想把那几个操作按钮提出来到标题下面的时候,因为标题在App组件中,那么按钮就需要移动到App组件里
  • 当我们移动到组件中的时候,点击按钮,发现会报错,this.props为空对象,并没有history属性
  • 这时候我们就需要借助withRouter,来封装一下自己的组件并且export default暴露出自己被封装过的组件即可

9.1、代码

import React, { Component } from "react";

// 从这里引入 withRouter
import { Route, Switch, withRouter} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";

class App extends Component {
  render() {
    return <div className="app">
      <h1>React Router Dom</h1>
      <button onClick={() => this.props.history.goBack()}>goBack回退</button>
      <button onClick={() => this.props.history.goForward()}>goForward前进</button>
      <button onClick={() => this.props.history.go(-1)}>go(-1)后退1</button>
      <button onClick={() => this.props.history.go(1)}>go(1)前进1</button>
      <div className="main">
        <div className="leftToolBar">
          <MyNavLink to="/home">Home</MyNavLink>
          <MyNavLink replace to="/about" children="About" />
        </div>
        <div className="rightContent">
          <Switch>
            <Route path="/home" component={Home} />
            <Route path="/about" component={About} />
            {/* 如果上面路由都匹配不到,那么走下面的路由 */}
            <Redirect to="/home" />
          </Switch>
          
        </div>
      </div>
    </div>
  }
}

// 将自己的组件交给 withRouter 包装,那么就可以使用 this.props.history
export default withRouter(App);

9.2、效果

在这里插入图片描述

10、BrowserRouter与HashRouter区别

  1. 底层原理不一样
    1. BrowserRouter使用的是H5的history API,不兼容IE9及以下版本兼容性
    2. HashRouter使用的是URL的哈希值
  2. path表现形式不一样
    1. BrowserRouter的路径中没有#,例如localhost:3000/about/message
    2. HashRouter的路径包含#,例如localhost:3000/#/about/message
  3. 刷新后对路由state参数的影响
    1. BrowserRouter没有任何影响,因为state保存在history对象中
    2. HashRouter刷新后会导致路由state参数丢失
  4. 备注:HashRouter可以用于解决一些路径错误相关的问题
React Router 是用于在 React 应用中实现路由的库。react-router-dom 是基于React Router 的适用于Web应用的扩展,它提供了一些额外的功能和组件。 下面是 react-router-dom v5 的使用教程: 1. 安装react-router-dom:打开终端并在项目目录下运行以下命令: ``` npm install react-router-dom ``` 2. 在你的应用入口文件中引入 `BrowserRouter` 和 `Route` 组件: ```jsx import React from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom'; function App() { return ( <Router> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Router> ); } export default App; ``` 3. 创建组件并将其与路由关联: ```jsx import React from 'react'; function Home() { return <h1>Home</h1>; } function About() { return <h1>About</h1>; } export { Home, About }; ``` 4. 在你的应用中使用 `<Link>` 组件创建导航链接: ```jsx import React from 'react'; import { Link } from 'react-router-dom'; function Navigation() { return ( <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> </ul> </nav> ); } export default Navigation; ``` 5. 在应用中渲染导航和路由: ```jsx import React from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom'; import Navigation from './Navigation'; import { Home, About } from './pages'; function App() { return ( <Router> <Navigation /> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Router> ); } export default App; ``` 现在你就可以在应用中导航到不同的页面了!注意,`exact` 属性用于确保只有在路径完全匹配时才会渲染组件。 这是一个简单的例子,你可以根据自己的需求进行更多的配置和使用。你可以在 react-router-dom 的官方文档中找到更多详细的信息和示例。 希望这个教程对你有帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值