react-router-dom

简介

  • react的一个插件库
  • 专门用来

基本使用

import React, { Component } from 'react'
import { Link, NavLink, Route, Switch,Redirect } from 'react-router-dom'
import './App.css'
import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'



//创建并暴露App组件,在使用App组件时,需要在<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>
export default class App extends Component {

render() {
  return (
    <div>

      <div className="row">
        <div className="col-xs-2 col-xs-offset-2">

          {/* 
          路由链接可以使用Link或者NavLink,NavLink可以通过activeClassName指定链接
          激活(点击)时添加的类名,默认指定的类名是active可以对NavLink进行二次封装
          */}

          <Link className="list-group-item" to='/about'>About</Link>
          <Link replace={true} className="list-group-item" to='/home'>Home</Link>
          {/*
          上面 replace={true} 表示 开启的replace模式,还有一种push模式(默认),replace
          模式可以实现无痕访问,先访问 /about 然后访问 /home,因为/home开启了replace模式,
          访问 /home 时会将 前面的访问记录替换掉,而不是追加一个访问记录
          */}


          <NavLink className="list-group-item" to='/about' activeClassName='active'>About</NavLink>
          <NavLink className="list-group-item" to='/home' activeClassName='active'>Home</NavLink >
        </div>
        <div className="col-xs-6">

          <Switch>
            {/*
            Switch标签中的路由匹配上一个就不继续匹配了'./home' 匹配上 组件Home  
            就不继续匹配 Test组件了*/}
            <Route exact={true} path='/about' component={About}></Route>
            {/*
            exact={true}表示严格匹配,默认开启的默认匹配,上面的一行代
            码给'/about'开启了严格匹配,那么它的多级路由都无法正确匹配
            了Link标签中to属性的路径和Route标签中path属性的路径一模一
            样时才能展示对应的组件to(Link)~/home/a/b/,path(Route)~/home,
            可以展示对应的组件 to(Link)~/a/home/b/,path(Route)~/home,
            不能展示对应的组件 to(Link)~/home,path(Route)~/home/a/b,
            不能展示对应的组件
            */}
            <Route path='/home' component={Home}></Route>
            <Route path='/home' component={Test}></Route>

            <Redirect to='/home'></Redirect>
            {/*
            Redirect一般写在路由的最下面,当所有的路由都匹配不上的
            时候就会按照Recirect来跳转
            */}
          </Switch>

        </div>
      </div>
    </div>
  )
}

}


嵌套路由

//这里是home组件
import React, { Component } from 'react'
import MyNavLink from '../../components/MyNavLink'
import { Route, Switch, Redirect } from 'react-router-dom'
import News1 from './News1'
import Message1 from './Message1'

export default class Home extends Component {
  return (
    <div>
      <h3>我是Home的内容</h3>
      <div>
        <ul className="nav nav-tabs">
          <li>
            <MyNavLink to='/home/news'>News1</MyNavLink>
            {/*
            to属性的值必须带上一级路由,而且一级路由中不能开启严格匹配
            */}
          </li>
          <li>
            <MyNavLink to='/home/messsage'>Messages1</MyNavLink>
          </li>
        </ul>
        <Switch>
          <Route path='/home/new' component={News1}></Route>
          {/*
          path属性的值必须带上一级路由
          */}

          <Route path='/home/new' component={Message1}></Route>

          <Redirect to="/home/new" />
        </Switch>

      </div>
    </div>
  )
}
}


路由传参

传递params参数

总结

  • 路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情

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

  • 接收参数:this.props.match.params

//home组件中
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component {
render() {
  state = {
    messageArr: [
      { id: '01', title: '消息1' },
      { id: '02', title: '消息2' },
      { id: '03', title: '消息3' },
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((item) => {
              return  (
                <li key={item.id}>
                <Link to={`/home/detail/${item.id}/${item.title}`}>{item.title}</Link>
                {/* 
                  需要在路由链接中携带params参数,注意需要在注册路由时声明
                  */}
              </li>
              )
            })
          }

        </ul>
        <hr />

        <Route path='/home/detail/:id/:title' component={Detail}></Route>
        {/*在注册路由中声明*/}

      </div>
    )
  }
}

//detail组件中
import React, { Component } from 'react'

const DetailData = [
  { id: '01', content: '你好,中国' },
  { id: '02', content: '你好,尚硅谷' },
  { id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
  render() {
    const { id, title } = this.props.match.params
    {
      /*
    接收params参数
    在路由组件中 通过this.props.match.params 可以接收到传递过来的paramas参数
    */
    }
    const findResult = DetailData.find(item => {
      return item.id === id
    })
    return (
      <ul>
        <li>ID:{id}</li>
        <li>title:{title}</li>
        <li>ID:{findResult.content}</li>
      </ul>
    )
  }
}


传递search参数

总结

  • 路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情

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

  • 接收参数:this.props.location.search,获取到的search是urlencoded编码字符串,需要借助querystring库解析

//home组件中
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './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.id}>
                {/* 向路由组件传递search参数 */}
                <Link to={`/home/detail/?id=${msgObj.id}&title=${msgObj.title}`}>
                  {msgObj.title}
                </Link>
              </li>
            )
          })}
        </ul>
        <hr />

        {/* search参数无需声明接收,正常注册路由即可 */}
        <Route path='/home/detail' component={Detail} />
      </div>
    )
  }
}


//detail组件中
import React, { Component } from 'react'
import qs from 'querystring'

const DetailData = [
  { id: '01', content: '你好,中国' },
  { id: '02', content: '你好,尚硅谷' },
  { id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
  render() {
    console.log(this.props)

    // 接收search参数
    const { search } = this.props.location
    const { id, title } = qs.parse(search.slice(1))
    {/*
	在路由组件中,this.props.loaction.search获得到的是形如 ?id=01&title='消息1'的
	数据
	urlencoded格式:id=01&title='消息1'
	querystring库可以处理urlencoded格式
	qs.parse(需要转化urlencoded的数据)===>转化为对象格式
	qs.stringfy(需要转化对象的数据)===>转化为urlencoded格式

     */}

    const findResult = DetailData.find(detailObj => {
      return detailObj.id === id
    })
    return (
      <ul>
        <li>ID:{id}</li>
        <li>TITLE:{title}</li>
        <li>CONTENT:{findResult.content}</li>
      </ul>
    )
  }
}



传递state参数

总结

  • 路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情

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

  • 接收参数:this.props.location.state,刷新也不会丢失数据

//home组件
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './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.id}>
                {/* 向路由组件传递state参数,Link的to属性要写成对象形式 */}
                <Link
                  to={{
                    pathname: '/home/detail',
                    state: { id: msgObj.id, title: msgObj.title }
                  }}
                >
                  {msgObj.title}
                </Link>
              </li>
            )
          })}
        </ul>
        <hr />

        {/* state参数无需声明接收,正常注册路由即可 */}
        <Route path="/home/message/detail" component={Detail} />
      </div>
    )
  }
}

//detail组件中接收数据
import React, { Component } from 'react'

const DetailData = [
  { id: '01', content: '你好,中国' },
  { id: '02', content: '你好,尚硅谷' },
  { id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
  render() {
    // 接收state参数
    const { id, title } = this.props.location.state || {}

    const findResult =
      DetailData.find(detailObj => {
        return detailObj.id === id
      }) || {}
    return (
      <ul>
        <li>ID:{id}</li>
        <li>TITLE:{title}</li>
        <li>CONTENT:{findResult.content}</li>
      </ul>
    )
  }
}



编程式路由导航

路由组件

路由组件的props对象上有history对象,history身上有很多API可以实现路由跳转

  • this.prosp.history.push(path, state),同样可以传递 params,search,state数据

  • this.prosp.history.replace(path, state),同样可以传递 params,search,state数据

  • this.prosp.history.goBack()

  • this.prosp.history.goForward()

  • this.prosp.history.go()


一般组件

react-router-dom库中有个withRouter方法,可以将一般组件的props添加上路由组件身上所有的那些属性,如下,可以通过 this.props.history调用API 实现条状路由
image

 import React, { Component } from 'react'
 import { withRouter } from 'react-router-dom'
 class Header extends Component {
 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="page-header">
         <h2>React Router Demo</h2>
         <button onClick={this.back}>回退</button>&nbsp;
         <button onClick={this.forward}>前进</button>&nbsp;
         <button onClick={this.go}>go</button>
       </div>
     )
   }
 }

export default withRouter(Header)

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

BrowerRouter和HashRouter的区别

  • 底层原理不一样:

    • BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
    • HashRouter使用的是URL的哈希值。
  • path表现形式不一样

    • BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
    • HashRouter的路径包含#,例如:localhost:3000/#/demo/test
  • 刷新后对路由state参数的影响

    • BrowserRouter没有任何影响,因为state保存在history对象中。
    • HashRouter刷新后会导致路由state参数的丢失!!!
  • 备注:HashRouter可以用于解决一些路径错误相关的问题。

组件懒加载

  • 通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包const Login = lazy(()=>import('@/pages/Login'))

  • 通过指定在加载得到路由打包文件前显示一个自定义loading界面

<Suspense fallback={}>
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
</Suspense>
import React, { Component, lazy, Suspense } from 'react'
import { NavLink, Route } from 'react-router-dom'

import Loading from './Loading'
//1.引入组件时要用lazy函数引入
const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))

 export default class Demo extends Component {
   render() {
     return (
       <div>
           <div className="list-group">
             {/* 在React中靠路由链接实现切换组件--编写路由链接 */}
             <NavLink className="list-group-item" to="/about">About</NavLink>
             <NavLink className="list-group-item" to="/home">Home</NavLink>
           </div>
         <div>
               <Suspense fallback={<Loading />}>
                //需要懒加载的组件需要用Supense标签包裹,并通过fallback指定一个组件或者DOM,
	          表示当懒加载的组件没有请求回来时展示的内容
                 {/* 注册路由 */}
                   <Route path="/about" component={About} />
                   <Route path="/home" component={Home} />
               </Suspense>
         </div>
      </div>
     )
   }
 }
posted @ 2021-10-13 16:30  Fen~  阅读(52)  评论(0)    收藏  举报