第5天:React路由

  • 以下代码示例的参考代码只提供源码文件夹/src目录下的文件。
  • 静态资源文件夹因为都一样,所以就不提供了,可以点击这里下载public目录
  • *代码的使用:根据步骤3.1.2执行完之后,替换掉相关文件夹即可。

5.1. 相关理解

中文文档
安装路由模块:npm i react-router-dom -S

路由的基本使用

  1. 明确好界面中的导航区、展示区

  2. 导航区的a标签改为Link标签
    <Link to="/xxxxx">Demo</Link>

  3. 展示区写Route标签进行路径的匹配
    <Route path='/xxxx' component={Demo}/>

  4. <App>的最外侧包裹了一个<BrowserRouter><HashRouter>

路由组件与一般组件

  1. 写法不同:
    一般组件:<Demo/>
    路由组件:<Route path="/demo" component={Demo}/>

  2. 存放位置不同:
    一般组件:components
    路由组件:pages

  3. 接收到的props不同:
    一般组件:写组件标签时传递了什么,就能收到什么
    路由组件:接收到三个固定的属性

    history:
        go: ƒ go(n)
        goBack: ƒ goBack()
        goForward: ƒ goForward()
        push: ƒ push(path, state)
        replace: ƒ replace(path, state)
    //
    location:
        pathname: "/about"
        search: ""
        state: undefined
    //
    match:
        params: {}
        path: "/about"
        url: "/about"

5.1.1. SPA的理解

  1. 单页Web应用(single page web application,SPA)。
  2. 整个应用只有一个完整的页面。
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

5.1.2. 路由的理解

  1. 什么是路由?

  2. 一个路由就是一个映射关系(`key:value`)

  3. `key`为路径, `value`可能是`function`或`component`

  4. 路由分类

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

  6. 前端路由:
    1) 浏览器端路由,`value`是`component`,用于展示页面内容。
    2) 注册路由: `<Route path="/test" component={Test}>`
    3) 作过程:当浏览器的`path`变为`/test`时, 当前路由组件就会变为Test组件

5.1.3. react-router-dom的理解

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

5.2. react-router-dom相关API

5.2.1. 内置组件

  1. `<BrowserRouter>`
  2. `<HashRouter>`
  3. `<Route>`
  4. `<Redirect>`
  5. `<Link>`
  6. `<NavLink>`
  7. `<Switch>`

5.2.2. 其它

  1. history对象
  2. match对象
  3. withRouter函数

5.3. 基本路由使用

5.3.1. 效果

  • src/App.jsx

    import React, { Component } from 'react'
    import {Link,Route} from 'react-router-dom'
    import Home from './components/Home'
    import About from './components/About'
    //
    export default class App extends Component {
    render() {
        return (
            

    React Router Demo

    {/* 原生html中,靠跳转不同的页面 */} {/* About Home */} {/* 在React中靠路由链接实现切换组件--编写路由链接 */} About Home
    {/* 注册路由 */}
    ) } }
  • src/index.js

    //引入react核心库
    import React from 'react'
    //引入ReactDOM
    import ReactDOM from 'react-dom'
    //
    import {BrowserRouter} from 'react-router-dom'
    //引入App
    import App from './App'
    //
    ReactDOM.render(
    
        
    ,
    document.getElementById('root')
    )
  • src/components/About/index.jsx

    import React, { Component } from 'react'
    //
    export default class About extends Component {
    render() {
        return (
            

    我是About的内容

    ) } }
  • src/components/Home/index.jsx

    import React, { Component } from 'react'
    //
    export default class Home extends Component {
    render() {
        return (
            

    我是Home的内容

    ) } }

5.3.2. 准备

  1. 下载react-router-dom: `npm install –save react-router-dom`
  2. 引入bootstrap.css: `<link rel="stylesheet" href="/css/bootstrap.css">`

5.4. 嵌套路由使用

  • src/App.jsx

    import React, { Component } from 'react'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import Home from './pages/Home' //Home是路由组件
    import About from './pages/About' //About是路由组件
    import Header from './components/Header' //Header是一般组件
    import MyNavLink from './components/MyNavLink'
    //
    export default class App extends Component {
    render() {
        return (
            
    {/* 原生html中,靠跳转不同的页面 */} {/* About Home */} {/* 在React中靠路由链接实现切换组件--编写路由链接 */} About Home
    {/* 注册路由 */}
    ) } }
  • src/index.js

    //引入react核心库
    import React from 'react'
    //引入ReactDOM
    import ReactDOM from 'react-dom'
    //
    import {BrowserRouter} from 'react-router-dom'
    //引入App
    import App from './App'
    //
    ReactDOM.render(
    
        
    ,
    document.getElementById('root')
    )
  • src/components/Header/index.jsx

    import React, { Component } from 'react'
    //
    export default class Header extends Component {
    render() {
        // console.log('Header组件收到的props是',this.props);
        return (
            

    React Router Demo

    ) } }
  • src/components/MyNavLink/index.jsx

    import React, { Component } from 'react'
    import {NavLink} from 'react-router-dom'
    //
    export default class MyNavLink extends Component {
    render() {
        // console.log(this.props);
        return (
            
        )
    }
    }
  • src/pages/About/index.jsx

    import React, { Component } from 'react'
    //
    export default class About extends Component {
    render() {
        // console.log('About组件收到的props是',this.props);
        return (
            

    我是About的内容

    ) } }
  • src/pages/Home/index.jsx

    import React, { Component } from 'react'
    import MyNavLink from '../../components/MyNavLink'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import News from './News'
    import Message from './Message'
    //
    export default class Home extends Component {
    render() {
        return (
                

    我是Home的内容

    • News
    • Message
    {/* 注册路由 */}
    ) } }
  • src/pages/Home/Message/index.jsx

    import React, { Component } from 'react'
    //
    export default class Message extends Component {
    render() {
        return (
            
        )
    }
    }
  • src/pages/Home/News/index.jsx

    import React, { Component } from 'react'
    //
    export default class News extends Component {
    render() {
        return (
            
    • news001
    • news002
    • news003
    ) } }

5.5. 向路由组件传递参数数据

5.5.1. 向路由组件传递params参数

  • src/App.jsx

    import React, { Component } from 'react'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import Home from './pages/Home' //Home是路由组件
    import About from './pages/About' //About是路由组件
    import Header from './components/Header' //Header是一般组件
    import MyNavLink from './components/MyNavLink'
    //
    export default class App extends Component {
    render() {
        return (
            
    {/* 原生html中,靠跳转不同的页面 */} {/* About Home */} {/* 在React中靠路由链接实现切换组件--编写路由链接 */} About Home
    {/* 注册路由 */}
    ) } }
  • src/index.js

    //引入react核心库
    import React from 'react'
    //引入ReactDOM
    import ReactDOM from 'react-dom'
    //
    import {BrowserRouter} from 'react-router-dom'
    //引入App
    import App from './App'
    //
    ReactDOM.render(
    
        
    ,
    document.getElementById('root')
    )
  • src/components/Header/index.jsx

    import React, { Component } from 'react'
    //
    export default class Header extends Component {
    render() {
        // console.log('Header组件收到的props是',this.props);
        return (
            

    React Router Demo

    ) } }
  • src/components/MyNavLink/index.jsx

    import React, { Component } from 'react'
    import {NavLink} from 'react-router-dom'
    //
    export default class MyNavLink extends Component {
    render() {
        // console.log(this.props);
        return (
            
        )
    }
    }
  • src/pages/About/index.jsx

    import React, { Component } from 'react'
    //
    export default class About extends Component {
    render() {
        // console.log('About组件收到的props是',this.props);
        return (
            

    我是About的内容

    ) } }
  • src/pages/Home/index.jsx

    import React, { Component } from 'react'
    import MyNavLink from '../../components/MyNavLink'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import News from './News'
    import Message from './Message'
    //
    export default class Home extends Component {
    render() {
        return (
                

    我是Home的内容

    • News
    • Message
    {/* 注册路由 */}
    ) } }
  • src/pages/Home/Message/index.jsx

    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 (
            
      { messageArr.map((msgObj)=>{ return (
    • {/* 向路由组件传递params参数 */} /home/message/detail/${msgObj.id}/${msgObj.title}}>{msgObj.title}
    • ) }) }

    {/* 声明接收params参数 */}
    ) } }
  • src/pages/Home/Message/Detail/index.jsx

    import React, { Component } from 'react'
    //
    const DetailData = [
    {id:'01',content:'你好,中国'},
    {id:'02',content:'你好,硅谷'},
    {id:'03',content:'你好,未来的自己'}
    ]
    export default class Detail extends Component {
    render() {
        console.log(this.props);
        // 接收params参数
        const {id,title} = this.props.match.params
        const findResult = DetailData.find((detailObj)=>{
            return detailObj.id === id
        })
        return (
            
    • ID:{id}
    • TITLE:{title}
    • CONTENT:{findResult.content}
    ) } }
  • src/pages/Home/News/index.jsx

    import React, { Component } from 'react'
    //
    export default class News extends Component {
    render() {
        return (
            
    • news001
    • news002
    • news003
    ) } }

5.5.2. 向路由组件传递search参数

  • src/App.jsx
    和5.5.1 的文件一样

  • src/index.js
    和5.5.1 的文件一样

  • src/components/Header/index.jsx
    和5.5.1 的文件一样

  • src/components/MyNavLink/index.jsx
    和5.5.1 的文件一样

  • src/pages/About/index.jsx
    和5.5.1 的文件一样

  • src/pages/Home/index.jsx

    import React, { Component } from 'react'
    import MyNavLink from '../../components/MyNavLink'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import News from './News'
    import Message from './Message'
    //
    export default class Home extends Component {
    render() {
        return (
                

    我是Home的内容

    • News
    • Message
    {/* 注册路由 */}
    ) } }
  • src/pages/Home/Message/index.jsx

    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 (
            
      { messageArr.map((msgObj)=>{ return (
    • {/* 向路由组件传递params参数 */} {/* /home/message/detail/${msgObj.id}/${msgObj.title}}>{msgObj.title} */} {/* 向路由组件传递search参数 */} /home/message/detail/?id=${msgObj.id}&title=${msgObj.title}}>{msgObj.title}
    • ) }) }

    {/* 声明接收params参数 */} {/* */} {/* search参数无需声明接收,正常注册路由即可 */}
    ) } }
  • src/pages/Home/Message/Detail/index.jsx

    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);
    
        // 接收params参数
        // const {id,title} = this.props.match.params 
    
        // 接收search参数
        const {search} = this.props.location
        const {id,title} = qs.parse(search.slice(1))
    
        const findResult = DetailData.find((detailObj)=>{
            return detailObj.id === id
        })
        return (
            
    • ID:{id}
    • TITLE:{title}
    • CONTENT:{findResult.content}
    ) } }
  • src/pages/Home/News/index.jsx
    和5.5.1 的文件一样

5.5.3. 向路由组件传递state参数

  • src/App.jsx
    和5.5.1 的文件一样

  • src/index.js
    和5.5.1 的文件一样

  • src/components/Header/index.jsx
    和5.5.1 的文件一样

  • src/components/MyNavLink/index.jsx
    和5.5.1 的文件一样

  • src/pages/About/index.jsx
    和5.5.1 的文件一样

  • src/pages/Home/index.jsx

    import React, { Component } from 'react'
    import MyNavLink from '../../components/MyNavLink'
    import {Route,Switch,Redirect} from 'react-router-dom'
    import News from './News'
    import Message from './Message'
    //
    export default class Home extends Component {
    render() {
        return (
                

    我是Home的内容

    • News
    • Message
    {/* 注册路由 */}
    ) } }
  • src/pages/Home/Message/index.jsx

    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 (
            
      { messageArr.map((msgObj)=>{ return (
    • {/* 向路由组件传递params参数 */} {/* /home/message/detail/${msgObj.id}/${msgObj.title}}>{msgObj.title} */} {/* 向路由组件传递search参数 */} {/* /home/message/detail/?id=${msgObj.id}&title=${msgObj.title}}>{msgObj.title} */} {/* 向路由组件传递state参数 */} {msgObj.title}
    • ) }) }

    {/* 声明接收params参数 */} {/* */} {/* search参数无需声明接收,正常注册路由即可 */} {/* */} {/* state参数无需声明接收,正常注册路由即可 */}
    ) } }
  • src/pages/Home/Message/Detail/index.jsx

    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);
    
        // 接收params参数
        // const {id,title} = this.props.match.params 
    
        // 接收search参数
        // const {search} = this.props.location
        // const {id,title} = qs.parse(search.slice(1))
    
        // 接收state参数
        const {id,title} = this.props.location.state || {}
    
        const findResult = DetailData.find((detailObj)=>{
            return detailObj.id === id
        }) || {}
        return (
            
    • ID:{id}
    • TITLE:{title}
    • CONTENT:{findResult.content}
    ) } }
  • src/pages/Home/News/index.jsx
    和5.5.1 的文件一样

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注