5_React路由

文章目录

1、理解
2、react-router-dom相关API
3、基本路由使用
4、嵌套路由使用(二级/多级路由)
5、向路由组件传递参数数据
6、编程式路由导航
7、withRouter的使用
8、BrowserRouter和HashRouter

一、理解

1、SPA页面

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

2、路由

一个路由就是一个key-value的映射关系,key为路径,value可能是function或component。

分类:

  • 后端路由

    1. value是function,用来解决客户端发出的请求
    2. 注册路由:router.get(path, function(req, res))
    3. 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
  • 前端路由(浏览器端路由)

    1. value是component,用来展示页面内容

    2. 注册路由:

    3. 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件

    4. 实现原理:利用BOM的history对象

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>前端路由的基石_history</title>
      </head>
      <body>
      	<a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a><br><br>
      	<button onClick="push('/test2')">push test2</button><br><br>
      	<button onClick="replace('/test3')">replace test3</button><br><br>
      	<button onClick="back()">&lt;= 回退</button>
      	<button onClick="forword()">前进 =&gt;</button>
      
      	<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
      	<script type="text/javascript">
      		// let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API
      		let history = History.createHashHistory() //方法二,hash值(锚点)
      
      		function push (path) {
                
                
      			history.push(path)
      			return false; // 不会跳转到新页面
      		}
      
      		function replace (path) {
                
                
      			history.replace(path)
      		}
      
      		function back() {
                
                
      			history.goBack()
      		}
      
      		function forword() {
                
                
      			history.goForward()
      		}
      
      		history.listen((location) => {
                
                
      			console.log('请求路由路径变化了', location)
      		})
      	</script>
      </body>
      </html>
      

3、 react-router-dom的理解

  • react的一个插件库
  • 专门用来实现一个SPA应用
  • 基于react项目基本都会用到此库

印记中文:网站,可找到很多前端的英文文档翻译为中文的

二、react-router-dom相关API

简单了解下

1、内置组件

  • BrowserRouter
  • HashRouter
  • Route
  • Redirect
  • Link
  • NavLink
  • Switch

2、其他

  • history对象
  • match对象
  • withRouter函数

三、基本路由使用

1、准备

下载react-router-dom: npm install --save react-router-dom

2、简单使用例子

// index.js
import App from './App'
import {
    
    BrowserRouter} from 'react-router-dom'
ReactDOM.render(
    {
    
    /* 直接在最外层包一个路由器,防止子组件内出现多个而不是同个路由器,无法跳转 */}
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

// app.jsx
import React, {
    
    Component} from 'react'
import {
    
    BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
    
    
  render() {
    
    
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {
    
    /* 原生html中,靠<a>跳转不同的页面 */}
              {
    
    /*<a className="list-group-item active" href="./about.html">About</a>
              <a className="list-group-item" href="./home.html">Home</a> */}
                
              {
    
    /* 在React靠路由链接实现切换组件--编写路由链接 */}
              {
    
    /* 一定不能在编写路由链接和注册路由,分别包一个<BrowserRouter>组件,防止不是同个路由器而无法跳转 */}
              <Link className="list-group-item" to="/about">About</Link>
              <Link className="list-group-item" to="/home">Home</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {
    
    /* 注册路由 */}
                <Route path='/about' componet={
    
    About}/>
                <Route path='/home' componet={
    
    Home}/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

// 组件home
import React, {
    
    Component} from 'react'
export default class Home extends Component {
    
    
  render() {
    
    
      return <h3>这是一个Home页面</h3>
  }
}

// 组件about
import React, {
    
    Component} from 'react'
export default class About extends Component {
    
    
  render() {
    
    
      return <h3>这是一个About页面</h3>
  }
}

NavLink组件和Link组件(都是编写路由链接,区别再于点击选中是否可有高亮的自定义样式)

{/* Link是最基本的路由链接 */}
<Link class="list-group-item" to="/about">About</Link>
<Link class="list-group-item" to="/home">Home</Link>

{/* Link是最基本的路由链接;若想点击有不同样式的需采用NavLink,点击默认会加样式名为active,或加个activeClassName的属性来定义点击后的样式名 */}
<NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>

Switch组件(放在注册路由的外层,用于检索到指定路由后就停止,不再全部路由全都检索一遍)

{/* 在外面包一层switch组件 */}
<Switch>
    <Route path='/about' componet={About}/>
    <Route path='/home' componet={Home}/>
</Switch>

3、总结

  • 明确好页面的导航区、展示区
  • 导航区中的a标签改为Link标签:Demo
  • 展示区去写Route标签进行路径的匹配:
  • App的最外侧包裹一个或
  • Route的外层可包裹一个Switch,按顺序检索到所指定的路由,就不继续往下检索其他的路由。当路由过多的话 ,每次更改一次就要全部去匹配一次,效率低。

4、路由组件和一般组件

  • 写法不同

    一般组件

    路由组件

  • 存放位置不同

    一般组件:components文件夹

    路由组件:page文件夹

  • 接收的props不同

    一般组件:写组件标签时传递了什么,就能收到什么

    路由组件:接收到3个固定的属性,如下所示

    1. history
      • go: f go(n)
      • goBack: f goBack()
      • goForward: f goForward()
      • push: f push(path, state)
      • replace: f replace(path, state)
    2. location
      • pathname: “/about”
      • search: “”
      • state: undefined
    3. match
      • params: {}
      • path: “/about”
      • url: “/about”

5、解决多级路径刷新页面样式丢失的问题

  • public/index.html中,引入样式时,不写 ./ ,写 / (常用)
  • public/index.html中,引入样式时,不写 ./ ,写 %PUBLICK_URL% (常用)
  • 使用HashRouter,浏览器路径会加#,#号后面的路径是不带到服务器上的

6、路由的模糊匹配与严格匹配exact

{/* 编写路由链接 */}
<Link class="list-group-item" to="/home/a/b/c">Home</Link>
{/* 注册路由 */}
<Route path='/home' componet={Home}/>
{/* 模糊匹配(默认),只要路由链接路径的前面部分,存在同注册路由一样的,是会匹配上的 */}

{/* 开启严格匹配,Route加个属性 exact={true} */}
<Route exact={true} path='/home' componet={Home}/>
<Route exact path='/home' componet={Home}/>
  • 默认使用的是模糊匹配(简单记:【输入的路径】必须包含【要匹配的路径】,且舒徐要一致)
  • 开启严格匹配:
  • 严格匹配不要随便开启,需要再开启,有时候开启会导致无法继续匹配二级路由

7、Redirct的使用

{/* 谁都匹配不上的时候,跳转到Redirct指定的路由 */}
<Route path='/about' componet={About}/>
<Route path='/home' componet={Home}/>
<Redirct to="/about" />

8、push与replace

默认路由跳转是:push,会留下记录,入栈history

replace是替换,不留下记录,替换栈顶

<Route path='/about' componet={
    
    About}/>

// 开启replace
<Route replace={
    
    true} path='/about' componet={
    
    About}/>

四、嵌套路由使用(二级/多级路由)

前提代码

// index.js
import App from './App'
import {
    
    BrowserRouter} from 'react-router-dom'
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

// app.jsx
import React, {
    
    Component} from 'react'
import {
    
    BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
    
    
  render(){
    
    
    retrun(
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">  
              {
    
    /* 编写路由链接 */}
              <NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
              <NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {
    
    /* 注册路由 */}
                <Switch>
                    <Route path='/about' componet={
    
    About}/>
                    <Route path='/home' componet={
    
    Home}/>
                    <Redirct to="/about" />
                 </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>}
}

// 组件about
import React, {
    
    Component} from 'react'
export default class About extends Component {
    
    
  render() {
    
    
      return <h3>这是一个About页面</h3>
  }
}

1、使用示例

// 组件home
import React, {
    
    Component} from 'react'
import {
    
     NavLink, Route } from 'react-router-dom'
import Message from './page/Home/Message'
import News from './page/News'
export default class Home extends Component {
    
    
  render(){
    
    
    return(
      <h3>这是一个Home页面</h3>
      <div>
          <ul className="nav-nav-tabs">
              {
    
    /* 编写路由链接 */}
              <li>
                  <NavLink activeClassName="active" class="list-group-item" to="/home/news">News</NavLink>
              </li>
              <li>
                  <NavLink activeClassName="active" class="list-group-item" to="/home/message">Message</NavLink>
              </li>
          </ul>
          {
    
    /* 注册路由 */}
          <Switch>
              <Route path='/home/news' componet={
    
    News}/>
              <Route path='/home/message' componet={
    
    Message}/>
              <Redirct to="/home/news" />
          </Switch>
      </div>
    )
  }
}

// 组件Message
import React, {
    
    Component} from 'react'
export default class Message extends Component {
    
    
  render(){
    
    
      <h3>这是一个Message组件</h3>
  }
}

// 组件News
import React, {
    
    Component} from 'react'
export default class News extends Component {
    
    
  render(){
    
    
      <h3>这是一个News组件</h3>
  }
}

2、总结

  • 注册子路由时要写上父路由的path
  • 路由的匹配时按照注册路由的顺序进行的

五、向路由组件传递参数数据

前提代码

// index.js
import App from './App'
import {
    
    BrowserRouter} from 'react-router-dom'
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

// app.jsx
import React, {
    
    Component} from 'react'
import {
    
    BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
    
    
  render() {
    
    
    return(
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">  
              {
    
    /* 编写路由链接 */}
              <NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
              <NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {
    
    /* 注册路由 */}
                <Switch>
                    <Route path='/about' componet={
    
    About}/>
                    <Route path='/home' componet={
    
    Home}/>
                    <Redirct to="/about" />
                 </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

// 组件about
import React, {
    
    Component} from 'react'
export default class About extends Component {
    
    
  render(){
    
    
      <h3>这是一个About页面</h3>
  }
}

// 组件home
import React, {
    
    Component} from 'react'
import {
    
     NavLink, Route } from 'react-router-dom'
import Message from './page/Home/Message'
import News from './page/News'
export default class Home extends Component {
    
    
  render() {
    
    
    retrun (
      <h3>这是一个Home页面</h3>
      <div>
          <ul className="nav-nav-tabs">
              {
    
    /* 编写路由链接 */}
              <li>
                  <NavLink activeClassName="active" class="list-group-item" to="/home/news">News</NavLink>
              </li>
              <li>
                  <NavLink activeClassName="active" class="list-group-item" to="/home/message">Message</NavLink>
              </li>
          </ul>
          {
    
    /* 注册路由 */}
          <Switch>
              <Route path='/home/news' componet={
    
    News}/>
              <Route path='/home/message' componet={
    
    Message}/>
              <Redirct to="/home/news" />
          </Switch>
      </div>
    )
  }
}

// 组件News
import React, {
    
    Component} from 'react'
export default class News extends Component {
    
    
  render() {
    
    
      return <h3>这是一个News组件</h3>
  }
}

1、params参数例子

// 组件Message
import React, {
    
    Component} from 'react'
import {
    
    Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/Detail'
export default class Message extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', title:'消息1'},
          {
    
    id:'02', title:'消息2'},
          {
    
    id:'03', title:'消息3'},
      ]
  }
  render() {
    
    
    const {
    
    messageArr} = this.state;
    return (
      <div>
          <ul>
              {
    
    
                  messageArr.map((msgObj) => {
    
    
                      return(
                          <li key={
    
    msgObj}>
                              {
    
    /* 向路由组件传递params参数 */}
                              <Link class="list-group-item" to={
    
    `/home/message/detail/${
      
      msgObj.id}/${
      
      msgObj.title}`}>{
    
    msgObj.title}</Link>
                          </li>
                      )
                  })
              }
          </ul>
          <hr />
          {
    
    /* 声明接收params参数 */}
          <Route path="/home/message/detail/:id/:title" component={
    
    Detail} />
      </div>
    )
  }
}

// 组件Detail
import React, {
    
    Component} from 'react'
export default class Detail extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', content:'内容1'},
          {
    
    id:'02', content:'内容2'},
          {
    
    id:'03', content:'内容3'},
      ]
  }
  render(){
    
    
      // 接收params参数
    const {
    
     id, title } = this.props.match.params;
    const currentObj = this.state.messageArr.find((obj) => {
    
    
        return obj.id = id;
    })
    return (
      <ul>
          <li>ID:{
    
    id}</li>
          <li>TITLE:{
    
    title}</li>
          <li>CONTENT:{
    
    currentObj.content}</li>
      </ul>
    )
  }
}

2、search参数例子

// 组件Message
import React, {
    
    Component} from 'react'
import qs from 'querystring'
import {
    
    Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/Detail'
export default class Message extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', title:'消息1'},
          {
    
    id:'02', title:'消息2'},
          {
    
    id:'03', title:'消息3'},
      ]
  }
  render() {
    
    
    const {
    
    messageArr} = this.state;
    return (
      <div>
          <ul>
              {
    
    
                  messageArr.map((msgObj) => {
    
    
                      return(
                          <li key={
    
    msgObj}>
                              {
    
    /* 向路由组件传递params参数 */}
                              {
    
    /* <Link class="list-group-item" to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}
                              
                              {
    
    /* 向路由组件传递search参数 */}
                              <Link class="list-group-item" to={
    
    `/home/message/detail?id=${
      
      msgObj.id}&title=${
      
      msgObj.title}`}>{
    
    msgObj.title}</Link>
                          </li>
                      )
                  })
              }
          </ul>
          <hr />
          {
    
    /* 声明接收params参数 */}
          {
    
    /* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
          
          {
    
    /* search参数无需声明接收,正常注册即可 */}
          <Route path="/home/message/detail" component={
    
    Detail} />
      </div>
    )
  }
}

// 组件Detail
import React, {
    
    Component} from 'react'
export default class Detail extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', content:'内容1'},
          {
    
    id:'02', content:'内容2'},
          {
    
    id:'03', content:'内容3'},
      ]
  }
  render(){
    
    
    // 接收params参数
   // const { id, title } = this.props.match.params;
    
    // 接收search参数
    const {
    
     search } = this.props.location;
    const {
    
     id, title } = qs.parse(search.silce(1));
    const currentObj = this.state.messageArr.find((obj) => {
    
    
        return obj.id = id;
    })
    retrun (
      <ul>
          <li>ID:{
    
    id}</li>
          <li>TITLE:{
    
    title}</li>
          <li>CONTENT:{
    
    currentObj.content}</li>
      </ul>
    )
  }
}

urlencoded => key=value&key=value

react可借助querystring库去解析地址参数

import qs from 'querystring';

let obj = {
    
    name: 'cyr', age: 18};
console.log(qs.stringfy(obj)); // 输出结果:name=cyr&age=18

let str = 'name=cyr&age=18';
console.log(qs.parse(str)); // 输出结果: Object{name: 'cyr', age: 18}

3、state参数

// 组件Message
import React, {
    
    Component} from 'react'
// import qs from 'querystring'
import {
    
    Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/Detail'
export default class Message extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', title:'消息1'},
          {
    
    id:'02', title:'消息2'},
          {
    
    id:'03', title:'消息3'},
      ]
  }
  render(){
    
    
    const {
    
    messageArr} = this.state;
    retrun (
      <div>
          <ul>
              {
    
    
                  messageArr.map((msgObj) => {
    
    
                      return(
                          <li key={
    
    msgObj}>
                              {
    
    /* 向路由组件传递params参数 */}
                              {
    
    /* <Link class="list-group-item" to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}
                              
                              {
    
    /* 向路由组件传递search参数 */}
                              {
    
    /* <Link class="list-group-item" to={`/home/message/detail?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
                              
                              {
    
    /* 向路由组件传递state参数 */}
                              <Link class="list-group-item" to={
    
    {
    
    pathname:'/home/message/detail', state:{
    
    id: msgObj.id, title: msgObj.title}}}>{
    
    msgObj.title}</Link>
                          </li>
                      )
                  })
              }
          </ul>
          <hr />
          {
    
    /* 声明接收params参数 */}
          {
    
    /* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
          
          {
    
    /* search参数无需声明接收,正常注册即可 */}
          {
    
    /* <Route path="/home/message/detail" component={Detail} /> */}
          
          {
    
    /* state参数无需声明接收,正常注册即可 */}
          <Route path="/home/message/detail" component={
    
    Detail} />
      </div>
    )
  }
}

// 组件Detail
import React, {
    
    Component} from 'react'
export default class Detail extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', content:'内容1'},
          {
    
    id:'02', content:'内容2'},
          {
    
    id:'03', content:'内容3'},
      ]
  }
  render(){
    
    
    // 接收params参数
    // const { id, title } = this.props.match.params;
    
    // 接收search参数
    // const { search } = this.props.location;
    // const { id, title } = qs.parse(search.silce(1));
    
    // 接收state参数
    const {
    
     id, title } = this.props.location.state || {
    
    };
    const currentObj = this.state.messageArr.find((obj) => {
    
    
        return obj.id = id;
    }) || {
    
    }return (
      <ul>
          <li>ID:{
    
    id}</li>
          <li>TITLE:{
    
    title}</li>
          <li>CONTENT:{
    
    currentObj.content}</li>
      </ul>
    )
  }
}

4、总结

  • params参数:

    (1)路由链接(携带参数):

      <Link to='/home/message/detail/1/测试‘}>详情</Link>
    

    (2)注册路由(声明接收):

      <Route path='/home/message/detail/:id/:title' component={Detail} />
    

    (3)接收参数:const { id, title } = this.props.match.params

  • search参数:

    (1)路由链接(携带参数):

      <Link to='/home/message/detail?id=1&title=测试‘}>详情</Link>
    

    (2)注册路由(无需声明接收,正常注册即可):

      <Route path='/home/message/detail' component={Detail} />
    

    (3)接收参数:const { search } = this.props.location

    (4)备注:获取到的search是urlencoded编码字符串,需要借助querystring解析

  • state参数:

    (1)路由链接(携带参数):

      <Link to={
         
         {pathname:'/home/message/detail', state:{id: msgObj.id, title: msgObj.title}}}>详情</Link>
    

    (2)注册路由(无需声明接收,正常注册即可):

      <Route path='/home/message/detail' component={Detail} />
    

    (3)接收参数:const { id, title} = this.props.location.state

    (4)浏览器路由路劲未带所传的参数,刷新是否可读取到? 可以的,因参数是放在浏览器的history对象的state里面(其中 this.props.location同 this.props.history的location是同一个的);但浏览器清楚缓存后再访问页面,参数就读取不到

六、编程式路由导航

1、示例

// 组件Message
import React, {
    
    Component} from 'react'
// import qs from 'querystring'
import {
    
    Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/Detail'
export default class Message extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', title:'消息1'},
          {
    
    id:'02', title:'消息2'},
          {
    
    id:'03', title:'消息3'},
      ]
  }
 
  replaceShow = (id, title) => {
    
    
      // replace跳转 + 携带params参数
      this.props.history.replace(`/home/message/detail/${
      
      id}/${
      
      title}`);
      
      // replace跳转 + 携带search参数
      // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`);
      
      // replace跳转 + 携带state参数
      // this.props.history.replace('/home/message/detail', {id, title});
  }
    
  pushShow = (id, title) => {
    
    
      // push跳转 + 携带params参数
      this.props.history.push(`/home/message/detail/${
      
      id}/${
      
      title}`);
      
      // push跳转 + 携带search参数
      // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
      
      // push跳转 + 携带state参数
      // this.props.history.push('/home/message/detail', {id, title});
  }
    
  back = () => {
    
    
      this.props.history.goBack();
  }
    
  forward = () => {
    
    
      this.props.history.goForward();
  }
    
  go = () => {
    
    
      this.props.history.go(2);
  }
  
  render(){
    
    
    const {
    
    messageArr} = this.state;
    return (
      <div>
          <ul>
              {
    
    
                  messageArr.map((msgObj) => {
    
    
                      return(
                          <li key={
    
    msgObj}>
                              {
    
    /* 向路由组件传递params参数 */}
                              <Link class="list-group-item" to={
    
    `/home/message/detail/${
      
      msgObj.id}/${
      
      msgObj.title}`}>{
    
    msgObj.title}</Link>
                              
                              {
    
    /* 向路由组件传递search参数 */}
                              {
    
    /* <Link class="list-group-item" to={`/home/message/detail?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
                              
                              {
    
    /* 向路由组件传递state参数 */}
                              {
    
    /* <Link class="list-group-item" to={
    
    {pathname:'/home/message/detail', state:{id: msgObj.id, title: msgObj.title}}}>{msgObj.title}</Link> */}
                               &nbsp;<button onClick={
    
    () => this.pushShow(msgObj.id, msgObj.title)}>push查看</button>
                              &nbsp;<button onClick={
    
    () => this.replaceShow(msgObj.id, msgObj.title)}>replace查看</button>
                          </li>
                      )
                  })
              }
          </ul>
          <hr />
          {
    
    /* 声明接收params参数 */}
          <Route path="/home/message/detail/:id/:title" component={
    
    Detail} />
          
          {
    
    /* search参数无需声明接收,正常注册即可 */}
          {
    
    /* <Route path="/home/message/detail" component={Detail} /> */}
          
          {
    
    /* state参数无需声明接收,正常注册即可 */}
          {
    
    /* <Route path="/home/message/detail" component={Detail} /> */}
          
          <button onClick={
    
    this.back}>回退</button>&nbsp;
          <button onClick={
    
    this.forward}>前进</button>&nbsp;
          <button onClick={
    
    this.go}>go前进/回退n步</button>
      </div>
    )
  }
}

// 组件Detail
import React, {
    
    Component} from 'react'
export default class Detail extends Component {
    
    
  state = {
    
    
      messageArr: [
          {
    
    id:'01', content:'内容1'},
          {
    
    id:'02', content:'内容2'},
          {
    
    id:'03', content:'内容3'},
      ]
  }
  render(){
    
    
    // 接收params参数
    const {
    
     id, title } = this.props.match.params;
    
    // 接收search参数
    // const { search } = this.props.location;
    // const { id, title } = qs.parse(search.silce(1));
    
    // 接收state参数
    // const { id, title } = this.props.location.state || {};
    const currentObj = this.state.messageArr.find((obj) => {
    
    
        return obj.id = id;
    }) || {
    
    }return (
      <ul>
          <li>ID:{
    
    id}</li>
          <li>TITLE:{
    
    title}</li>
          <li>CONTENT:{
    
    currentObj.content}</li>
      </ul>
    )
  }
}

2、总结

借助this.props.history对象上的API对操作路由跳转、前进、后退

  • this.props.history.push(path[, state])
  • this.props.history.replace(path[, state])
  • this.props.history.goBack()
  • this.props.history.goForward()
  • this.props.history.go(n)

七、withRouter的使用

如何让一般组件也能用上路由组件的方法?

前提代码

// index.js
import App from './App'
import {
    
    BrowserRouter} from 'react-router-dom'
ReactDOM.render(
    {
    
    /* 直接在最外层包一个路由器,防止子组件内出现多个而不是同个路由器,无法跳转 */}
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

// app.jsx
import React, {
    
    Component} from 'react'
import {
    
    BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Header from './component/Header'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
    
    
  render() {
    
    
    retrun (
      <div>
        <div className="row">
          <Header />
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {
    
    /* 原生html中,靠<a>跳转不同的页面 */}
              {
    
    /*<a className="list-group-item active" href="./about.html">About</a>
              <a className="list-group-item" href="./home.html">Home</a> */}
                
              {
    
    /* 在React靠路由链接实现切换组件--编写路由链接 */}
              {
    
    /* 一定不能在编写路由链接和注册路由,分别包一个<BrowserRouter>组件,防止不是同个路由器而无法跳转 */}
              <Link className="list-group-item" to="/about">About</Link>
              <Link className="list-group-item" to="/home">Home</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {
    
    /* 注册路由 */}
                <Route path='/about' componet={
    
    About}/>
                <Route path='/home' componet={
    
    Home}/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

// 组件home
import React, {
    
    Component} from 'react'
export default class Home extends Component {
    
    
  render() {
    
    
      return <h3>这是一个Home页面</h3>
  }
}

// 组件about
import React, {
    
    Component} from 'react'
export default class About extends Component {
    
    
  render() {
    
    
      return <h3>这是一个About页面</h3>
  }
}


1、示例

// 一般组件Header
import React, {
    
    Component} from 'react'
import {
    
    withRouter} from 'react-router-dom'

class Header extends Componet {
    
    
  back = () => {
    
    
      this.props.history.goBack();
  }
    
  forward = () => {
    
    
      this.props.history.goForward();
  }
    
  go = () => {
    
    
      this.props.history.go(2);
  }
  
  render() {
    
    
    console.log('Header组件收到的props是', this.props);
    return (
      <div className="col-xs-offset-2 col-xs-8">
        <div className="page-header"><h2>React Router Demo</h2></div>
        <button onClick={
    
    this.back}>回退</button>&nbsp;
        <button onClick={
    
    this.forward}>前进</button>&nbsp;
        <button onClick={
    
    this.go}>go前进/回退n步</button>
      </div>
    )
  }
}

export defalut withRouter(Header)

2、总结

  • withRouter是个函数
  • withRouter可以加工一般组件,让一般组件具备路由组件所持有的API
  • withRouter的返回值是一个新组件

八、BrowserRouter和HashRouter

1、底层原理不同

  • BrowserRouter: 使用的是H5的history API,不兼容IE9以下的版本
  • HashRouter: 使用的是URL的哈希值

2、path表现形式不同

  • BrowserRouter: 路径没有#,如:localhost:3000/demo/test
  • HashRouter: 路径包含#,#号后面的参数不会发给服务器,如:localhost:3000/#/demo/test

3、刷新后对路由state参数的影响

  • BrowserRouter: 没有任何影响,因为state保存在history对象中
  • HashRouter: 刷新后,会导致state参数丢失

4、备注:HashRouter可以用于解决一些路由错误的相关问题

猜你喜欢

转载自blog.csdn.net/weixin_43899065/article/details/128192872