React学习(7)路由

路由的理解

  • 1)什么是路由?
    a. 一个路由就是一个映射关系(key:value)
    b. key为路由路径, value可能是function/component
  • 2)路由分类
    a. 后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据
    b. 前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件
  • 3)后台路由
    a. 注册路由: router.get(path, function(req, res))
    b. 当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
  • 4)前端路由
    a. 注册路由: <Route path="/about" component={About}>
    b. 当浏览器的hash变为/about时, 当前路由组件就会变为About组件

react-router相关API

react-router是伴随着react框架出现的路由系统,它也是公认的一种优秀的路由解决方案。在使用react-router时候,我们常常会使用其自带的路径跳转组件Link,通过<Link to="path"></Link>实现跳转,这和传统的<a href="path"></a>何其相似!但它们到底有什么具体的区别呢
对比<a>,Link组件避免了不必要的重渲染
react-router:只更新变化的部分从而减少DOM性能消耗

组件

  • 1)路由方案,路由方案的一种形式
    browserHistory 使用的是 HTML5pushState API来修改浏览器的历史记录
    需要服务器端做配置,路径是真实的URL,是官方推荐首选
    为什么browserHistory需要服务端配置?,因为真实URL其实是指向服务器资源,比如我们经常使用的API接口,也是一个真实URL的资源路径,当通过真实URL访问网站的时候,第一次访问的是网站的域名,这个时候可以正常加载我们的网站js等文件,而用户手动刷新网页时,由于路径是指向服务器的真实路径,服务器端没有做路由配置,就会导致资源不存在,用户访问的资源不存在,返回给用户的是404错误。
    通过hashHistory来生成的URL就不会出现这样的问题,因为他不是指向真实的路由
    两种方式的特点
    1.History API 提供了 pushState()replaceState() 方法来增加或替换历史记录。而 hash 没有相应的方法,所以browserHistory有替换历史记录的功能,hashHistory没有
    2.hashHistory实现简单,不需要做额外的服务端改造
  • 2)<HashRouter>
    hashHistory 是通过改变地址后面的 hash(也就是URL中#后面的值) 来改变浏览器的历史记录
    不需要服务器配置,在URL生成一个哈希来跟踪状态,通常在测试环境使用,也可以作为发布环境使用

  • 3)<Route>路由组件,注册路由
    Route组件的Props对象中包含有path和component两个属性
    path属性:URL的路径
    component属性: 当匹配到 URL 时,单个的组件会被渲染。它可以 被父 route 组件的 this.props.children 渲染

  • 4)<Router>路由器组件,用来包含各个路由器组件,管理路由器

  • 5)<Redirect>标签通过自动重写URL来将浏览器重定向至一个新的URL

  • 6)<Link>路由链接组件,生成a标签的,<Link>时,url会更新,组件会被重新渲染,但是页面不会重新加载

  • 7)<NavLink><Link>的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有
    activeClassName(string):设置选中样式,默认值为active
    activeStyle(object):当元素被选中时,为此元素添加样式
    exact(bool):为true时,只有当导致和完全匹配class和style才会应用
    strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线

  • 8)标签,则其中的在路径相同的情况下,只匹配第一个,这个可以避免重复匹配

基本路由使用

  • 实现效果:

  • 静态html下载
    点击下载

  • 安装react-router

yarn add react-router-dom
  • index.js代码:
import React from 'react'
import ReactDOM from 'react-dom'
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 {NavLink, Route, Redirect, Switch} from 'react-router-dom'
import About from "./pages/About"
import Home from './pages/Home'

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 className="list-group-item" to="/about">About</NavLink>
                            <NavLink className="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' component={About}/>
                                    <Route path='/home' component={Home}/>
                                    <Redirect to='/about'/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}
  • pages/About.jsx代码:
import React, {Component} from "react"

export default class About extends Component {
    render() {
        return <h3>这是About页面的内容</h3>
    }
}
  • pages/Home.jsx代码:
import React, {Component} from "react"

export default class Home extends Component {
    render() {
        return <h3>这是Home页面的内容</h3>
    }
}

嵌套路由使用

实现效果:

  • pages/Home.jsx代码:
import React, {Component} from "react"
import {NavLink, Redirect, Route, Switch} from 'react-router-dom'
import HomeNews from "./HomeNews"
import HomeMessages from "./HomeMessages"

export default class Home extends Component {
    render() {
        return (
            <div><h2>Home组件内容</h2>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" to="/home/message">Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path='/home/news' component={HomeNews}/>
                        <Route path='/home/message' component={HomeMessages}/>
                        <Redirect to='/home/news'/>
                    </Switch>
                </div>
            </div>
        )
    }
}
  • pages/HomeNews.jsx代码:
import React, {Component} from "react"

export default class HomeNews extends Component {
    render() {
        return (
            <ul>
                <li>news001</li>
                <li>news002</li>
                <li>news003</li>
            </ul>
        )
    }
}
  • pages/HomeMessages.jsx代码:
import React, {Component} from "react"

export default class HomeMessages extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        <a href="/home/message/1">message001</a>  
                        <button>push查看</button>  
                        <button>replace查看</button>
                    </li>
                    <li>
                        <a href="/home/message/3">message003</a>  
                        <button>push查看</button>  
                        <button>replace查看</button>
                    </li>
                    <li>
                        <a href="/home/message/5">message005</a>  
                        <button>push查看</button>  
                        <button>replace查看</button>
                    </li>
                </ul>
                <button>回退</button>
                <hr/>
            </div>
        )
    }
}

封装NavLink

  • src\components\MyNavLink.jsx内容如下:
import React, {Component} from "react"
import {NavLink} from 'react-router-dom'

export default class MyNavLink extends Component {
    render() {
        let props = this.props
        return <NavLink className="list-group-item" {...props}></NavLink>
    }
}
  • src\pages\Home.jsx内容修改如下:
import React, {Component} from "react"
import {Redirect, Route, Switch} from 'react-router-dom'
import MyNavLink from '../components/MyNavLink'
import HomeNews from "./HomeNews"
import HomeMessages from "./HomeMessages"

export default class Home extends Component {
    render() {
        return (
            <div><h2>Home组件内容</h2>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <MyNavLink to="/home/news">News</MyNavLink>
                        </li>
                        <li>
                            <MyNavLink to="/home/message">Message</MyNavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path='/home/news' component={HomeNews}/>
                        <Route path='/home/message' component={HomeMessages}/>
                        <Redirect to='/home/news'/>
                    </Switch>
                </div>
            </div>
        )
    }
}

路由组件传参

  • 实现效果:

src\pages\HomeMessages.jsx内容如下:

import React, {Component} from "react"
import {Link, Route} from 'react-router-dom'
import HomeMessagesDetail from "./HomeMessagesDetail";

export default class HomeMessages extends Component {
    state = {
        messages: []
    }

    componentDidMount() {
        this.setState({
            messages:[
                {mid:1,content:'message1'},
                {mid:2,content:'message2'},
                {mid:3,content:'message3'},
                {mid:4,content:'message4'},
                {mid:5,content:'message5'},
            ]
        })
    }

    render() {
        return (
            <div>
                <ul>
                    {
                        this.state.messages.map((item)=>{
                            return (
                                <li key={item.mid}>
                                    <Link to={`/home/message/detail/${item.mid}`}>{item.content}</Link>&nbsp;&nbsp;
                                    <button>push查看</button>
                                    &nbsp;&nbsp;
                                    <button>replace查看</button>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr/>
                <Route path="/home/message/detail/:id" component={HomeMessagesDetail}/>
                <hr/>
                <button>回退</button>

            </div>
        )
    }
}

src\pages\HomeMessagesDetail.jsx内容如下:

import React, {Component} from "react"

export default class HomeMessagesDetail extends Component {
    state = {
        messages:[
            {id:1,title:'message1',content:'这是message1的内容'},
            {id:2,title:'message2',content:'这是message2的内容'},
            {id:3,title:'message3',content:'这是message3的内容'},
            {id:4,title:'message4',content:'这是message4的内容'},
            {id:5,title:'message5',content:'这是message5的内容'},
        ]
    }

    render() {
        let {id} = this.props.match.params
        let {messages} = this.state
        let messageTarget = messages.find((item)=>{
            return item.id===parseInt(id)
        })
        return (
            <ul>
                <li>ID: {id}</li>
                <li>TITLE: {messageTarget.title}</li>
                <li>CONTENT: {messageTarget.content}</li>
            </ul>

        )
    }
}

编程式路由导航

  • 声明式导航
    <link><NavLink> 实现路由的跳转是声明式导航
  • 编程式导航
    通过js路由对象的方式叫做编程式导航 push replace go

编程式导航:

类别 使用方法
push props.history.push('/singer')
replace props.history.replace({pathname:'/singer'})
go props.history.go(-1)  //返回
goback props.history.goBack()  //返回
goforward props.history.goForward()  //前进
  • DEMO实现效果:

\src\pages\HomeMessages.jsx的文件代码:

import React, {Component} from "react"
import {Link, Route} from 'react-router-dom'
import HomeMessagesDetail from "./HomeMessagesDetail";

export default class HomeMessages extends Component {
    state = {
        messages: []
    }

    componentDidMount() {
        this.setState({
            messages: [
                {mid: 1, content: 'message1'},
                {mid: 2, content: 'message2'},
                {mid: 3, content: 'message3'},
                {mid: 4, content: 'message4'},
                {mid: 5, content: 'message5'},
            ]
        })
    }

    pushShow = (path) => {
        this.props.history.push(path)
    }

    replaceShow = (path) => {
        this.props.history.replace(path)
    }

    goBack = () => {
        this.props.history.goBack()
    }

    goForward = () => {
        this.props.history.goForward()
    }

    render() {
        return (
            <div>
                <ul>
                    {
                        this.state.messages.map((item) => {
                            return (
                                <li key={item.mid}>
                                    <Link to={`/home/message/detail/${item.mid}`}>{item.content}</Link>&nbsp;&nbsp;
                                    <button onClick={() => {
                                        return this.pushShow(`/home/message/detail/${item.mid}`)
                                    }}>push查看
                                    </button>
                                    &nbsp;&nbsp;
                                    <button onClick={() => {
                                        return this.replaceShow(`/home/message/detail/${item.mid}`)
                                    }}>replace查看</button>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr/>
                <Route path="/home/message/detail/:id" component={HomeMessagesDetail}/>
                <hr/>
                <button onClick={() => {
                    return this.goBack()
                }}>回退</button>
                &nbsp;&nbsp;
                <button onClick={() => {
                    return this.goForward()
                }}>前进</button>

            </div>
        )
    }
}

发表评论

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