react-router的使用步骤

1,065 阅读8分钟

单页和多页

  • SPA: Single Page Application 单页面应用程序,整个应用中只有一个页面(index.html)
  • MPA : Multiple Page Application多页面应用程序,整个应用中有很多个页面(*.html)

优点

  1. 加快页面响应速度,降低了对服务器的压力

    • 传统的多页面应用程序,每次请求服务器返回的都是一整个完整的页面
    • 单页面应用程序只有第一次会加载完整的页面,以后每次请求仅仅获取必要的数据
  2. 更好的用户体验,运行更加流畅

image.png

缺点

不利于 SEO 搜索引擎优化

  • 因为 爬虫 只爬取 HTML 页面中的文本内容,不会执行 JS 代码

  • 可以通过 SSR(服务端渲染 Server Side Rendering)来解决 SEO 问题

    • 解释:先在服务器端把内容渲染出来,然后,返回给浏览器的就是纯 HTML 内容了
  • 页面静态化,比如,对于一个电商应用可以为每一个商品生产一个静态的HTML页面,静态 HTML 页面中是带有文字内容的,所以,有利于 SEO 的

React 路由介绍

现代的前端应用大多都是 SPA(单页应用程序),也就是只有一个 HTML 页面的应用程序。因为它的用户体验更好、对服务器的压力更小,所以更受欢迎。为了有效的使用单个页面来管理原来多页面的功能,前端路由应运而生。前端路由的功能:让用户从一个视图(页面)导航到另一个视图(页面)

  • 前端路由是一套映射规则,在React中,是 URL路径组件 的对应关系
  • 使用 React 路由简单来说就是:配置路径和组件(配对)

image.png

image.png

react模拟hash路由的实现

实现原理

hash值: localhost:3000/#/page1

#之后的部分就是hash值,它有两个特点:

  1. hash值的变化(地址栏中改了hash值再回车)不会重新发请求。它不是请求路径的一部分。
  2. hash值的变化会触发hashChange事件。

目录结构

pages/Comment.jsx
pages/Home.jsx
pages/Search.jsx
index.js

index.js

import React, { useEffect, useState } from 'react'
import Home from './pages/Home.jsx'
import Search from './pages/Search.jsx'
import Comment from './pages/Comment.jsx'

import ReactDom from 'react-dom'

export default function App () {
  const [curHash, setCurHash] = useState('')

  useEffect(() => {
    const onChange = () => {
      // console.log(window.location.hash)
      setCurHash(window.location.hash.slice(1))
    }
    onChange()
    window.addEventListener('hashchange', onChange)
    return () => {
      window.removeEventListener('hashchange', onChange)
    }
  }, [])
  return (
    <div>
      <ul>
        <li>
          <a href="#/home">首页</a>
        </li>
        <li>
          <a href="#/comment">评论</a>
        </li>
        <li>
          <a href="#/search">搜索</a>
        </li>
      </ul>
      <hr />
      {curHash === '/home' && <Home />}
      {curHash === '/search' && <Search />}
      {curHash === '/comment' && <Comment />}
    </div>
  )
}

ReactDom.render(<App />, document.getElementById('root'))

React路由使用的基本

版本

v5.reactrouter.com/ (5.X)

React-router提供了一些router的核心api,包括Router, Route, Switch等,但是它没有提供dom操作进行跳转的api

步骤

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

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

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

    1. 使用HashRouter包裹整个应用,一个项目中只会有一个Router
  3. 使用Link指定导航链接

    1. 使用Route指定路由规则(哪个路径展示哪个组件)

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'))

路由三大对象之-Router

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

两种常用 Router:HashRouterBrowserRouter

  • HashRouter:使用 URL 的哈希值实现(http://localhost:3000/#/first

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

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

命名

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

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

路由三大对象之-Link

Link

Link组件最终会渲染成a标签,用于指定路由导航

  • to属性,将来会渲染成a标签的href属性
  • Link组件无法展示哪个link处于选中的效果

NavLink

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

格式:

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

说明:

  • to属性,用于指定地址,会渲染成a标签的href属性
  • activeClassName: 用于指定高亮的类名,默认active。一般不去修改。
  • exact: 精确匹配,表示必须地址栏和to的属性值 精确匹配类名才生效

测试代码

import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter as Router, Route, Link, NavLink } from 'react-router-dom'
import Search from './pages/Search.jsx'
import Comment from './pages/Comment.jsx'
export default function App () {
  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>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

总结

  1. link和NavLink都用来做路由跳转。它们都用****属性来指定跳转地址
  2. link和NavLink的区别是,NavLink指向的路径会自带一个名为 active的css类名

路由三大对象之-Route

route的作用和格式

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

匹配规则

名词约定:

  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'))

exact

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

总结

  • path 的说明

    • 默认情况下,/能够匹配任意/开始的路径
    • 如果 path 的路径匹配上了,那么就可以对应的组件就会被 render
  • exact , exact 表示精确匹配某个路径

    • 一般来说,如果路径配置了 /, 都需要配置 exact 属性

Switch与404

Switch

用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'))

处理404页

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

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>
const Page404 = () => <div>Page404</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} />
          <Route component={Page404} />
        </Switch>
      </Router>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

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

页面跳转 Redirect

格式

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

示例代码

import React from 'react'
import ReactDom from 'react-dom'
import { HashRouter, Route, Link, Redirect } 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>
     		<Switch>
          <Link to="/comment">评论</Link>
          <Link to="/search">搜索</Link>


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

编程式导航

页面跳转有两类方式:

  1. 用户点击链接跳转
  2. 写代码跳转-编程式导航

编程式导航的格式

import {useHistory} from 'react-router'

export default function App() {
  const history = useHistory()
  
  history.push('/find')
  // 前进或后退到某个页面,参数 n 表示前进或后退页面数量(比如:-1 表示后退到上一页)
  history.go(-1) 
  
  // 进入/frend,并替换记录
  history.replace('/frend') 
  
}

history.replace和push的区别

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

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

示例

push

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

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

replace

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

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

image.png

动态路由与路由参数获取

动态路由

// 可以匹配 /article/1  /article/2  /article/xxx
<Route path="/article/:id" component={Article} />

说明:

  1. 上面的/:id 称为占位符。id可以改成其他的变量名。
  2. 占位符可以有多个。例如: /article/:形参1/:形参2

在组件中接收到路由的参数

有两个方式:

  1. 通过props可以
function Article(props){
    console.log(props.match.params.id)
}
  1. 通过hooks可以
impoirt { useParams } from 'react-router'
const params = useParams()
console.log(params) // 这里有数据

嵌套路由的配置

核心代码

App () {
  return 
    <Router>
      <ul>
        <li><NavLink to="/find">发现</NavLink></li>
        <li><NavLink to="/my">我的音乐</NavLink></li>
          <li><NavLink to="/frend">朋友</NavLink></li>
      </ul>

      <Switch>
           <Route path="/find" component={Find}></Route>
          <Route path="/my" component={My}></Route>
          <Route path="/frend" component={Frend}></Route>
      </Switch>
    </Router>
}

Find.js

Find(){
  return <Router>
    <ul>
    	<li><NavLink to="/find/recommand">推荐</NavLink></li>
      <li><NavLink to="/find/top">排行榜</NavLink></li>
       <li><NavLink to="/find/list">歌单</NavLink></li>
    </ul>
  
    <Switch>
         <Route path="/find/recommand" component={Com1}></Route>
  			<Route path="/my/top" component={Com2}></Route>
  			<Route path="/frend/list" component={Com3}></Route>
    </Switch>
    </Router>
}

注意

配置嵌套路由的时候,需要对路径进行处理,必须要先匹配到父级路由,才能匹配到子路由

路由总结

用到的组件

HashRouter, BrowserRouter, Link, NavLink, Route, Redirect, Switch

执行过程

  1. 点击 Link 组件(a标签),修改了浏览器地址栏中的 url
  2. React 路由监听到地址栏 url 的变化 hashChange popState
  3. React 路由内部遍历所有 Route 组件,使用路由规则(path)与 pathname(hash)进行匹配
  4. 当路由规则(path)能够匹配地址栏中的 pathname(hash) 时,就展示该 Route 组件的内容

宝,你都看到这了不给我一个star嘛?

PS:   如果内容有错误的地方欢迎指出(觉得看着不理解不舒服想吐槽也完全没问题);如果有帮助,欢迎点赞和收藏,转载请著明出处,如果有问题也欢迎私信交流