初识react-router

环境介绍

当前使用的版本为:

"react-router-dom": "^4.3.1"

react-router 与 react-router-dom

可以认为react-router 为 react-router-dom 的子集
比如以下写法:

import { HashHistory, Switch, Route, Router, Link } from 'react-router-dom'
// 等价于
import { Switch, Route, Router } from 'react-router'
import { HashHistory, Link } from 'react-router-dom'

react-router 实现了路由的核心功能。 react-router-dom 是基于react-router,加入了浏览器操作的一些功能。所以只需要下载依赖react-router-dom就可以了。以下是记录react-router-dom的简单使用。

Link 与 NavLink

Link 的用法

import { Link } from 'react-router-dom'
<Link to='/about'></Link>

<Link 
    to={{
        pathname:'/about',
        search: "?sort=name",
        hash: "#the-hash",
        state: { fromDashboard: true }
    }} />
    
<Link to='/about' replace />
//用过vue的,对这个比较清楚,添加这个不会把该路由添加到访问的历史记录里。

pathname: (string)路由名称。
search:(string)查询参数的字符串表示形式。
hash:添加hash值到url里,可对应路由。
state: 在路由里添加含有状态的变量,根据变量,来对路由做相应的处理。

NavLink

<Link /> 组件里的特殊组件。当前url匹配时,为该元素添加样式属性。比如table切换的时候,选中的一栏字体高亮等。

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

<NavLink to="/about">About</NavLink> // 一般用法

<NavLink to="/about" activeClassName="selected">About</NavLink>  // 添加激活的时的class

<NavLink
  to="/about"
  activeStyle={{
    fontWeight: "bold",
    color: "red"
  }}
>
  About
</NavLink>  
// 可以直接添加样式

Redirect

重定向重新加载页面。

import { Route, Redirect } from 'react-router'

// 如果未登录,重定向登录界面
<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/loggedIn" />
  ) : (
    <HomePage/>
  )
)}/>

// to: string
<Redirect to="/list/id" />

// to: Object
<Redirect
  to={{
    pathname: "/login",
    search: "?utm=your+face",
    state: { referrer: currentLocation }
  }}
/>

// from: string
<Redirect from='/old-path' to='/new-path'/>
<Redirect from='/users/:id' to='/users/profile/:id'/>

这边简单实现比较常用的table切换,用到的重定向的问题。下面实现当从一个页面跳转到一个table切换的页面,默认重定向已通过的模块(也可以定向到其他页面,根据自己需求,设置type值。这里需要注意的一点是,如果当前页面是首页的话,就不能使用this.props.match.path, 因为路由match对象还不存在,如果想在首页实现的话,就不要加this.props.match.path)。

import React from 'react';
import { NavLink, Switch, Route, Redirect } from 'react-router-dom';
class App extends React.Component {
    render(){
        return(
            <div>
                <NavLink to={`${this.props.match.path}/passed`} className="nav-link">已通过</NavLink>
                <NavLink to={`${this.props.match.path}/audited`} className="nav-link">待审核</NavLink>
                <NavLink to={`${this.props.match.path}/failed`} className="nav-link">未通过</NavLink>
                <!--子路由在父级配置-->
                <Switch>
                  <Route path={`${this.props.match.path}/:type`} component={Content} />
                  <Redirect from={`${this.props.match.path}`} to={`${this.props.match.path}/passed`} exact component={Content} />
                </Switch>
            </div>
        )
    }
}

Route

是最基本的组件,当url匹配时,渲染对应的组件。

import { Router, Route } from 'react-router-dom';
<Router>
    <Route exact path="/" component={Home} /> 
</Router>

// 获取传递的参数
<Route path="/user/:username" component={User} />;

function User({ match }) {
  return <h1>Hello {match.params.username}!</h1>;
}

// 或者可以这样
class User extends Component{
    constructor(props){
        super(props)
    }
    render(){
        return  <h1>Hello { this.props.match.params.username}!</h1>;
    }
}

这边还有route 路由渲染函数式表达,来处理过度动画,点击这里

Router

路由器的初级出口
常用的几种方式

import { BrowserRouter as Router } from 'react-router';

import { HashRouter as Router } from 'react-router';

import { Router  } from 'react-router';
import createBrowserHistory from "history/createBrowserHistory";

const history = createBrowserHistory()

<Router history={history}>
  <App/>
</Router>

Switch

常用来包裹<Route /> 和<Redirect /> 组件;

withRouter

顾名思义,是来关联路由。下面有使用到,也可以和react-redux一起使用,这里只介绍react-router部分。

react-router-dom 的简单的使用

这里我们实现两个路由跳转的案例来介绍路由的使用

  • 比较常见的页面之间的跳转
image

我们先实现基本的骨架

<!--// app.js-->
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';

class App extends Component { 
    nextPage = () => {
        this.props.history.push('/test')
    }
    render(){
        return (
            <div>
                <ul>
                    <li><NavLink to='/about'> About </NavLink></li>
                    <li><NavLink to='/inbox'> Inbox </NavLink></li>
                </ul>
                <div onClick={ this.nextPage }>测试<div>
            </div>
        )
    }
}
// about.js
import React from 'react'
const About = () => {
    return <h2>About</h2>
}
export default About;

//inbox.js
import React from 'react'
const Inbox = () => {
    return <h2>Inbox</h2>
}
export default Inbox;
// test.js
import React from 'react'
const Test = () => {
    return <h2>这是个测试</h2>
}
export default Test;

// router.js
import React from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import App from './App'
import About from './about' 
import Inbox from './Inbox'
import Test from './test'

class Routes extends React.Component {
  render(){
    return (
      <BrowserRouter>
        <Switch>
            <Route path='/' exact component={App}/> // exact 是精确匹配,如果没有这个,会匹配所有带有/的路由
            <Route path='/about' component={About}/>
            <Route path='/inbox' component={Inbox}/>
            <Route path='/test' exact component={Test}/>
        </Switch>
      </BrowserRouter>
    )
  }
}
export default Routes;
// index.js 
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './router'
ReactDOM.render(<Routes />, document.getElementById('root'));
  • 这里render函数return的对象,必须要有一个跟标签,来包裹内容。如果不想要根标签,react还提供了<Fragment />组件来包裹内容。这里需要注意的是,还是需要提供的<Fragment /> 包裹内容,并且需要引入(和Component一样)。
  • 实现页面内的内容切换


    image

这里我们只需要对两个文件改动就可以了。一个是App.js, 一个是router.js。其他页面我们不动。

// App.js 修改为:
class App extends Component { 
    nextPage = () => {
        this.props.history.push('/test')
    }
    render(){
        return (
            <div>
                <ul>
                    <li><NavLink to='/about'> About </NavLink></li>
                    <li><NavLink to='/inbox'> Inbox </NavLink></li>
                </ul>
                <div onClick={ this.nextPage }>测试<div>
                { this.props.children }
            </div>
        )
    }
}
// router.js修改为:
class Routes extends React.Component {
  render(){
    return (
      <BrowserRouter>
        <Switch>
          <App>
            <Route path='/about' component={About}/>
            <Route path='/inbox' component={Inbox}/>
          </App>
          <Route path='/test' exact component={Test}/>
        </Switch>
      </BrowserRouter>
    )
  }
}

这里我们基本就是实现了页面内组件内容的切换了,但是此时出现了一个问题,当我点击‘测试’ 的时候,页面报错了。报错内容为“ TypeError: Cannot read property 'push' of undefined ” ,可以看出路由并没有匹配到,得到的是一个undefind。因为该组件没有关联到路由,这里需要(react-router-dom中的withRouter组件)关联下。

import React, { Component } from 'react'
import { NavLink, withRouter } from 'react-router-dom'

class App extends Component {
  nextPage = () => {
    this.props.history.push('/test');
  }
  render() {
    return (
      <div>
        <ul>
          <li><NavLink to="/about"> About </NavLink> </li>
          <li><NavLink to="/inbox"> Inbox </NavLink></li>
        </ul>
        <div onClick={this.nextPage} >测试</div>
        { this.props.children }
      </div>
    );
  }
}
export default withRouter(App);

但是还是没有跳转,额...

这边看下路由,尝试调整路由的位置

class Routes extends React.Component {
  render(){
    return (
      <BrowserRouter>
        <Switch>
          <Route path='/test' exact component={Test}/>
          <App>
            <Route path='/about' component={About}/>
            <Route path='/inbox' component={Inbox}/>
          </App>
        </Switch>
      </BrowserRouter>
    )
  }
}

嗯,搞定。在当前页面切换不同组件内容,并实现页面间的路由跳转。

这里只是简单的使用react-router实现两种跳转方式,使用js控制路由的跳转,以及不同组件的使用,这里还有BrowserRouter HashRouterStaticRouterlocationmatchmatchPath等。react-router还有很多强大的功能,这里只是用了基础的,后续会慢慢记录学习react以及相关插件。

具体参考官方文档, 因为网上有很多不同版本的介绍,感觉很乱,还是应该先查阅官方文档,如果不明白的地方,在具体查阅网上介绍,注意版本的区别。

如有不正确的地方,还请大佬斧正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容