最近学习了 react-router v4,根据官方 API 文档和网上资源做了一个简单的路由示例。

先用官方的工具 create-react-app  初始化一个 react 项目模板,再根据自己的需要修改。

要实现的路由:

1. 登录页(/login)

2. 主页(/home):一级导航

3. 商品管理(/goods):一级导航

4. 商品列表(/goods/list):二级导航

5. 商品品牌(/goods/brand):二级导航

6. 路由重定向:

(1)未登录时,地址栏输入主域名(localhost:3000),页面重定向到登录页;否则,重定向到主页。

(2)点击一级导航“商品管理”时,重定向到其下的第一个子导航“商品列表”。

(3)退出后,重定向到登录页。

项目结构:

├── app
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── src
│ │ ├── assets
│ │ │ ├── app.css
│ │ │ └── logo.svg
│ │ ├── common
│ │ │ └── RouteWithSubRoutes.js
│ │ ├── modules
│ │ │ ├── asideContainer
│ │ │ │ └── Goods.js
│ │ │ ├── container
│ │ │ │ ├── Container.js
│ │ │ │ ├── Header.js
│ │ │ │ └── Home.js
│ │ │ ├── error
│ │ │ │ └── NotFound.js
│ │ │ ├── goods
│ │ │ │ ├── Brand.js
│ │ │ │ └── List.js
│ │ │ ├── login
│ │ │ │ └── Login.js
│ │ ├── index.js
│ │ ├── Routes.js
│ ├── .gitignore
│ ├── package-lock.json
│ ├── package.json
│ └── README.md

路由配置(src/Routes.js):

import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom' import RouteWithSubRoutes from './common/RouteWithSubRoutes.js'
import NotFound from './modules/error/NotFound.js'
import Login from './modules/login/Login.js'
import Container from './modules/container/Container.js'
import Home from './modules/container/Home.js'
import Goods from './modules/asideContainer/Goods.js'
import List from './modules/goods/List.js'
import Brand from './modules/goods/Brand.js' const routes = [
{
path: '/home',
component: Home
},
{
path: '/goods',
component: Goods,
children: [
{
path: '/goods/list',
component: List
},
{
path: '/goods/brand',
component: Brand
}
]
}
] export default () => (
<Router>
<Switch>
<Route path='/login' component={Login} />
<Container>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
<Route component={NotFound} />
</Switch>
</Container>
</Switch>
</Router>
)

重定向需要用到 Redirect 组件,但是我的经验就是,Redirect 不要与 Route 作为同级兄弟一起使用,否则页面会保持在 Redirect 指定的路由,而不能跳到其它的路由:

this.props.history.push 指定的路由就会无效。

RouteWithSubRoutes 参考的是官方的的示例。它是一个函数,接收一个对象作为参数,并返回一个(子)路由。在这里它用于渲染一级导航。

登录(src/modules/login/Login.js):

import React, { Component } from 'react'
import { Redirect } from 'react-router-dom' export default class Login extends Component {
constructor(props) {
super(props)
this.state = {
loggedIn: localStorage.getItem('loggedIn'),
username: 'anonymous',
password: '123'
} this.onInputChange = this.onInputChange.bind(this)
this.onSubmit = this.onSubmit.bind(this);
} onInputChange(event) {
const target = event.target
const name = target.name
const value = target.value this.setState({
[name]: value
})
} onSubmit(event) {
if (this.state.username && this.state.password) {
localStorage.setItem('loggedIn', true)
localStorage.setItem('username', this.state.username)
this.setState({loggedIn: true})
this.props.history.push('/home')
}
} render() {
if (this.state.loggedIn && this.props.location.pathname === '/login') {
return (
<Redirect to='/home' />
)
} return (
<div className='login-wrap'>
<h2>登 录</h2>
<div className='field-box'>
<label className='control-label'>用户名:</label>
<input type='text' name='username' value={this.state.username} onChange={this.onInputChange} />
</div>
<div className='field-box'>
<label className='control-label'>密 码:</label>
<input type='password' name='password' value={this.state.password} onChange={this.onInputChange} />
</div>
<div className='field-box'>
<label className='control-label'></label>
<button type='button' onClick={this.onSubmit}>登 录</button>
</div>
</div>
)
}
}

将用户名写入 localStorage,再通过 this.props.history.push('/home') 跳转到主页。

Container组件(src/modules/container/Container.js):

import React, { Component } from 'react'
import { Redirect } from 'react-router-dom' import Header from './Header' class Container extends Component {
constructor() {
super()
this.state = {
loggedIn: localStorage.getItem('loggedIn'),
test: 'it is a testing'
}
} render() {
if (!this.state.loggedIn) {
return (
<Redirect to='/login' />
)
} else if (this.props.location.pathname === '/') {
return (
<Redirect to='/home' />
)
} return (
<div>
<Header {...this.state} />
<div className='main-layout'>
{this.props.children}
</div>
</div>
)
}
} export default Container

判断用户是否登录,再通过 Redirect 重定向到相应的路由。

this.props.children 用于获取 Container 的子组件。

头部(src/modules/container/Header.js):

import React, { Component } from 'react'
import { NavLink, Redirect } from 'react-router-dom' export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
loggedIn: localStorage.getItem('loggedIn')
}
} onLogout = () => {
localStorage.setItem('loggedIn', '')
this.setState({loggedIn: false})
} render() {
if (!this.state.loggedIn) {
return (
<Redirect to='/login' />
)
} return (
<header className='fixed-top'>
<div className='pull-left'>
<h1>管理平台</h1>
<NavLink to='/home' exact>主页</NavLink>
<NavLink to='/goods'>商品管理</NavLink>
</div>
<div className='pull-right'>
<div className='header-info'>
欢迎您,{localStorage.getItem('username')}
<span style={{marginLeft: 10}}>|</span>
<a className='logout' onClick={this.onLogout}>退出</a>
</div>
</div>
</header>
)
}
}

退出后,清空 localStorage 中的 loggedIn,并重定向到登录页

<Redirect to='/login' />

商品管理(src/modules/asideContainer/Goods.js):

import React from 'react'
import { NavLink, Route, Redirect } from 'react-router-dom' import RouteWithSubRoutes from '../../common/RouteWithSubRoutes.js' export default ({ routes, path }) => (
<div>
<div className='aside-nav'>
<NavLink to="/goods/list">商品列表</NavLink>
<NavLink to="/goods/brand">商品品牌</NavLink>
</div> {
routes.map((route, i) => {
return (
<RouteWithSubRoutes key={i} {...route}/>
)
})
} <Route exact path='/goods' render={() => (
<Redirect to='goods/list' />
)} />
</div>
)

同样用到了 RouteWithSubRoutes, 在这里它用于渲染二级导航。

通过 Route 判断当前页是“商品管理”(exact 用于路由的严格匹配),再用 Redirect 重定向。

注意,当前路由处于 active 状态,用到的是 NavLink 组件;另一个类似功能的组件是 Link,但没有当前 active 状态。

回过头去看看 Header 组件:

<NavLink to='/home' exact>主页</NavLink>
<NavLink to='/goods'>商品管理</NavLink>

对于“主页”,添加了 exact 属性,但“商品管理”则没有,为什么?因为当路由跳转到“商品列表”(/goods/list)时,exact 严格匹配 /goods 的结果为 false,模糊匹配的结果才为 true。

更多细节,详见项目内容。

react-router v4 学习实践的更多相关文章

  1. [Web 前端] React Router v4 入坑指南

    cp from : https://www.jianshu.com/p/6a45e2dfc9d9 万恶的根源 距离React Router v4 正式发布也已经过去三个月了,这周把一个React的架子 ...

  2. React Router V4发布

    React Router V4 正式版发布,该版本相较于前面三个版本有根本性变化,遵循 Just Component 的 API 设计理念. 本次升级的主要变更有: 声明式 Declarative 可 ...

  3. [React Router v4] Intercept Route Changes

    If a user has entered some input, or the current Route is in a “dirty” state and we want to confirm ...

  4. [React Router v4] Redirect to Another Page

    Overriding a browser's current location without breaking the back button or causing an infinite redi ...

  5. [React Router v4] Render Multiple Components for the Same Route

    React Router v4 allows us to render Routes as components wherever we like in our components. This ca ...

  6. [React Router v4] Conditionally Render a Route with the Switch Component

    We often want to render a Route conditionally within our application. In React Router v4, the Route ...

  7. [React Router v4] Render Catch-All Routes with the Switch Component

    There are many cases where we will need a catch-all route in our web applications. This can include ...

  8. [React Router v4] Render Nested Routes

    With React Router v4 the entire library is built as a series of React components. That means that cr ...

  9. [React Router v4] Parse Query Parameters

    React Router v4 ignores query parameters entirely. That means that it is up to you to parse them so ...

  10. [React Router v4] Use Regular Expressions with Routes

    We can use regular expressions to more precisely define the paths to our routes in React Router v4. ...

随机推荐

  1. Bing必应地图中国API一显示地图 (转) 做人要厚道

    Bing必应地图中国API一显示地图 2011-05-24 14:27:31|  分类: Bing&Google|字号 订阅     微软必应地图中国地图API发布已经有10天了,考虑到网上现 ...

  2. USACO 刷题有感

    最近每天都尽量保持着每天一道USACO的题目,呵呵,一开始都是满简单的,一看题目基本上思路就哗啦啦地出来了,只不过代码实现有点麻烦,花了一些时间去调试,总体感觉还不错,但是越往后做,应该就很难保持一天 ...

  3. Java集合类解析 ***

    collection集合 Map集合 Hashtable和HashMap的区别: Hashtable的方法是同步的,而HashMap的方法不是.HashMap可以将空值作为一个表的条目的key或val ...

  4. uva1563

    https://vjudge.net/problem/UVA-1563 高斯消元解同余方程组 就是把原来的除法换成逆元,其他的都一样 #include<bits/stdc++.h> usi ...

  5. HTTP请求 响应状态码

      1.请求响应方式       get是从服务器上获取数据,post是向服务器传送数据.get 数据在地址栏中明文的形式发送, post则不是,传递的数据比get多 据RFC2616标准(现行的HT ...

  6. bzoj1770: [Usaco2009 Nov]lights 燈(折半搜索)

    1770: [Usaco2009 Nov]lights 燈 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1153  Solved: 564[Submi ...

  7. C#多线程,基础知识很重要

    本文通过介绍C#多线程的用法(基础玩法),附加介绍一下WinForm里边跨线程访问UI的方法 如图,就是这么一个简单的界面,每个按钮下面一个方法,分别设置文本框里边的内容,那么,开始吧! 先介绍一下W ...

  8. git 详细部署及其应用

    第1章 版本控制系统 自动生成备份.随时回滚.知道改动的地方. 1.1 svn和git的区别 1.1.1 svn 集中式的版本控制系统,只有一个中央数据仓库,如果中央数据库仓库挂了或者不可访问,所有的 ...

  9. serlvet HttpServletRequest

    1.http://localhost/az/servlet/TestResponse out.print("getServletPath:"+request.getServletP ...

  10. Poj 3694 Network (连通图缩点+LCA+并查集)

    题目链接: Poj 3694 Network 题目描述: 给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥? 解题思路: 先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条 ...