React router 使用及路由传参总结

8,296 阅读6分钟

1.React路由使用的基本

版本

react-router-dom现在发了6.0版本,目前不稳定。

使用步骤

  1. 安装包。npm i react-router-dom@5.3.0

    这个包提供了三个核心的组件:HashRouter(BrowserRouter), Route, Link

  2. 导入包,并使用。import { HashRouter, Route, Link } from 'react-router-dom'

    使用HashRouter包裹整个应用,一个项目中只会有一个Router

  3. 使用Link指定导航链接

  4. 使用Route指定路由规则(哪个路径展示哪个组件) renderchildren展示方式请参考React router 如何渲染(render和children)---访问控制

import React from 'react'
import ReactDom from 'react-dom'
import { HashRouter, Route, Link } from 'react-router-dom'
import Search from './pages/Search.jsx'
import Comment from './pages/Comment.jsx'
export default function App () {
  return (
    <div>
      <h1>react路由基本使用</h1>
      <HashRouter>
        <Link to="/comment">评论</Link>
        <Link to="/search">搜索</Link>

        <Route path="/comment" component={Comment} />
        <Route path="/search" component={Search} />
      </HashRouter>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

2.路由对象-Router

1.Router两种模式

HashRouter :hash模式

BrowserRouter: history模式

2.Router内部原理

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

两种常用 Router:HashRouterBrowserRouter

  • HashRouter:使用 URL 的哈希值实现

    • 原理:监听 window 的 hashchange 事件来实现的
  • (推荐)BrowserRouter:使用 H5 的 history.pushState() API 实现

    • 原理:监听 window 的 popstate 事件来实现的

3.常规用法

使用es6的导入重命名来统一名字: 无论导入的是哪个路由对象,都叫Router

import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import { HashRouter as Router, Route, Link } from 'react-router-dom'

3.路由对象Link和NavLink--声明式导航

Link和NavLink都能用来做跳转,最终都会被渲染成<a>内容</a>标签
import { Link, NavLink } from 'react-router-dom'

1.Link

Link组件无法展示哪个link处于选中的效果\

<Link to="/search">搜索</Link>

2.NavLink

NavLink组件,一个更特殊的Link组件,可以用于指定当前导航高亮

格式:

<NavLink to="/xxx" activeClassName="active">链接</NavLink>

说明:

  • to属性,用于指定地址,会渲染成a标签的href属性
  • activeClassName: 用于指定高亮的类名,默认active。一般不去修改
  return (
    <div>
      <h1>react路由基本使用-Link</h1>
      <Router>
        <div>
          Link:
          <Link to="/search">搜索</Link>
          <Link to="/comment">评论</Link>
        </div>
        <div>
          NavLink: 自带高亮类
          <NavLink to="/" exact>主页</NavLink>
          <NavLink to="/search">搜索</NavLink>
          <NavLink to="/comment">评论</NavLink>
        </div>
        <Route path="/comment" component={Comment} />
        <Route path="/search" component={Search} />
      </Router>
    </div>
  )

4.路由对象Route

route的作用和格式

  1. 作用: 决定路由匹配规则
  2. 格式:<Route path="/xx/xx" component={组件}></Route>

1.匹配规则

名词约定:

  1. path: Route组件中path属性的值

  2. pathname: 指的如下格式

    1. link组件中to的属性值
    2. 地址栏中的地址

模糊匹配规则

  1. 只要pathname以path开头就算匹配成功
  2. 匹配成功就加载对应组件;
  3. 整个匹配过程是逐一匹配,一个匹配成功了,并不会停止匹配

模糊匹配和精确匹配

  1. 默认是模糊匹配的!!!
  2. 补充exact可以设置成精确匹配
import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
const Home = () => <div>主页</div>
const Article = () => <div>文章列表页</div>
const ArticleDetail = () => <div>文章详情页</div>
export default function App () {
  return (
    <div>
      <h1>react路由基本使用</h1>
      <Router>
          // 导航
        <NavLink to="/">主页</NavLink>&nbsp;
        <NavLink to="/article">文章列表页</NavLink>&nbsp;
        <NavLink to="/article/123">文章详情页-123</NavLink>&nbsp;
        <hr />
        
         // 对应的跳转规则
        <Route path="/" component={Home} />
        <Route path="/article" component={Article} />
        <Route path="/article/123" component={ArticleDetail} />
      </Router>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

2.exact精确匹配

如下代码:
如果不加exact精确匹配,name所有以'/'开头的都会被这个path匹配到 ,如:'/home' , '/login'
加上exact精确匹配,只有在path为'/'的时候才能匹配到

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

5.Switch

1.用法:

用Switch组件包裹多个Route组件。

Switch组件下,不管有多少个Route的路由规则匹配成功,都只会渲染第一个匹配的组件

import React from 'react'
import ReactDom from 'react-dom'
import {
  BrowserRouter as Router,
  Route,
  NavLink,
  Switch
} from 'react-router-dom'
const Home = () => <div>主页</div>
const Article = () => <div>文章列表页</div>
const ArticleDetail = () => <div>文章详情页</div>
export default function App () {
  return (
    <div>
      <h1>react路由基本使用</h1>
      <Router>
        <NavLink to="/">主页</NavLink>&nbsp;
        <NavLink to="/article">文章列表页</NavLink>&nbsp;
        <NavLink to="/article/123">文章详情页-123</NavLink>&nbsp;
        <hr />
        
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/article" component={Article} />
          <Route path="/article/123" component={ArticleDetail} />
        </Switch>
      </Router>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

2. 404页面处理

通过Switch组件非常容易的就能实现404错误页面的提示

不设置path属性,将404页对应的路由放在switch内部的最后位置

       <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/article" component={Article} />
          <Route path="/article/123" component={ArticleDetail} />
          <Route component={Page404} />
       </Switch>

6.页面重定向 Redirect

如下代码:

匹配到from = '/'后 , 重定向到 "/comment"路径对应的组件
这里的from页可以改写成path效果一样

import { HashRouter, Route, Link, Redirect } from 'react-router-dom'

<Redirect from="/" exact  to="/comment"  />

7.react-router编程式导航

1.history对象

使用格式:

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

export default function App() {
  const history = useHistory()
  // 跳转到指定页面
  history.push('/home')
  
  // 前进或后退到某个页面,参数 n 表示前进或后退页面数量(比如:-1 表示后退到上一页)
  history.go(-1) 
  
  // 替换到当前页面,展示指定页面
  history.replace('/login') 
}

2.history.replace和push的区别

push:向历史记录中添加一条

replace:在历史记录中用目标记录来替换当前记录

示例

push:

详情页  --> login页(push)  ----> 主页 

此时,从主页后退,会回到login页。 replace

详情页  --> login页(replace)  ----> 主页 

此时,从主页后退,会回到详情页。

8.路由跳转传参

1.location对象

个人比较喜欢用location对象和state,search方式获取路由传值的操作,来看下location中有什么:

Snipaste_2021-11-19_20-37-28.png 如何在组件中获取location对象:

1.组件中的props对象包含了location:

export default function Article (props) {
  console.log('props对象', props) 
  return (
        <div>
            Article
        </div>
  )
}

打印结果如图: location.png

2.history中也包含了location对象

import { useHistory } from 'react-router-dom'
export default function Article () {
  const history = useHistory()
  console.log(history)
  return (
        <div>
            Article
        </div>
  )
}

打印结果如图:

history中的location.png

3.useLocation这个Hook获取

import { useLocation } from 'react-router-dom'
export default function Article () {
  const location = useLocation()
  console.log('使用useLocation获取的location', location)
  return (
        <div>
            Article
        </div>
  )
}

打印结果如图: 使用use hisahf .png

2.声明式导航的传参:

2.1.查询参数方式:

<Link to= '/home/article ?id=9 '>内容管理</Link>

2.2.对象写法:

// 传递单个id  (location.id拿值)
<Link to={{ pathname: '/home/article', id: 3 }}>内容管理</Link>

// 传递id 和 name (location.state拿值) 
//这里写的如果不是state:{要传递的参数} ,那么location中原有的state属性会被覆盖,还是使用原有的state吧
<Link to={{ pathname: '/home/article', state: {id:3 , name:'给我一个div'} }}>内容管理</Link>

2.3.接收数据:

再来看看传参之后location中有什么:
1.查询参数方式:

查询参数.png 2.对象写法

state接收.png

2.4.取值:

const value = location.state

const value = location.search

3.编程式导航的传参

同样的用location,search,state

   message.success('登录成功', 2, () => {
      //  做跳转动作 到主页中
        history.replace('/home?id=33')
      })

const value = location.search //结果: ?id=33 需要截取一下

  message.success('登录成功', 2, () => {
      //  做跳转动作 到主页中
        history.replace('/home', '给我一个div')
      })

const value = location.state //结果: 给我一个div

  message.success('登录成功', 2, () => {
      //  做跳转动作 到主页中
        history.replace('/home', { name: '给我一个div', id: 9 })
      })

const value = location.state // {name: '给我一个div', id: 9}

4.路由传值小结:

个人比较喜欢这种方式传参,跳转的时候直接给参数,全部在location中接收参数,并且拿到location的方式也很方便
另外还有params方式传参,props对象的match对象中有params对象,函数组件的话也可以使用useParams钩子 ,这里就不介绍了,想补充的兄弟欢迎在下面留言,有不对的地方欢迎指出