码迷,mamicode.com
首页 > 其他好文 > 详细

react-router v4 学习实践

时间:2017-07-03 17:22:54      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:api   实践   ade   参考   资源   不能   ref   favicon   login   

    最近学习了 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):

 1 import React, { Component } from ‘react‘
 2 
 3 export default class Login extends Component {
 4   constructor(props) {
 5     super(props)
 6     this.state = {
 7       loggedIn: localStorage.getItem(‘loggedIn‘),
 8       username: ‘anonymous‘,
 9       password: ‘123‘
10     }
11 
12     this.onInputChange = this.onInputChange.bind(this)
13     this.onSubmit = this.onSubmit.bind(this);
14   }
15 
16   onInputChange(event) {
17     const target = event.target
18     const name = target.name
19     const value = target.value
20 
21     this.setState({
22       [name]: value
23     })
24   }
25 
26   onSubmit(event) {
27     if (this.state.username && this.state.password) {
28       localStorage.setItem(‘loggedIn‘, true)
29       localStorage.setItem(‘username‘, this.state.username)
30       this.setState({loggedIn: true})
31       this.props.history.push(‘/home‘)
32     }
33   }
34 
35   render() {
36     return (
37       <div className=‘login-wrap‘>
38         <h2>登 录</h2>
39         <div className=‘field-box‘>
40           <label className=‘control-label‘>用户名:</label>
41           <input type=‘text‘ name=‘username‘ value={this.state.username} onChange={this.onInputChange} />
42         </div>
43         <div className=‘field-box‘>
44           <label className=‘control-label‘>密  码:</label>
45           <input type=‘password‘ name=‘password‘ value={this.state.password} onChange={this.onInputChange} />
46         </div>
47         <div className=‘field-box‘>
48           <label className=‘control-label‘></label>
49           <button type=‘button‘ onClick={this.onSubmit}>登 录</button>
50         </div>
51       </div>
52     )
53   }
54 }

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

 

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

 1 import React, { Component } from ‘react‘
 2 import { Redirect } from ‘react-router-dom‘
 3 
 4 import Header from ‘./Header‘
 5 
 6 class Container extends Component {
 7   constructor() {
 8     super()
 9     this.state = {
10       loggedIn: localStorage.getItem(‘loggedIn‘),
11       test: ‘it is a testing‘
12     }
13   }
14 
15   render() {
16     if (!this.state.loggedIn) {
17       return (
18         <Redirect to=‘/login‘ />
19       )
20     } else if (this.props.location.pathname === ‘/‘) {
21       return (
22         <Redirect to=‘/home‘ />
23       )
24     }
25 
26     return (
27       <div>
28         <Header {...this.state} />
29         <div className=‘main-layout‘>
30           {this.props.children}
31         </div>
32       </div>
33     )
34   }
35 }
36 
37 export default Container

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

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

 

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

 1 import React, { Component } from ‘react‘
 2 import { NavLink, Redirect } from ‘react-router-dom‘
 3 
 4 export default class Header extends Component {
 5   constructor(props) {
 6     super(props)
 7     this.state = {
 8       loggedIn: localStorage.getItem(‘loggedIn‘)
 9     }
10   }
11 
12   onLogout = () => {
13     localStorage.setItem(‘loggedIn‘, ‘‘)
14     this.setState({loggedIn: false})
15   }
16 
17   render() {
18     if (!this.state.loggedIn) {
19       return (
20         <Redirect to=‘/login‘ />
21       )
22     }
23 
24     return (
25       <header className=‘fixed-top‘>
26         <div className=‘pull-left‘>
27           <h1>管理平台</h1>
28           <NavLink to=‘/home‘ exact>主页</NavLink>
29           <NavLink to=‘/goods‘>商品管理</NavLink>
30         </div>
31         <div className=‘pull-right‘>
32           <div className=‘header-info‘>
33             欢迎您,{localStorage.getItem(‘username‘)}
34             <span style={{marginLeft: 10}}>|</span>
35             <a className=‘logout‘ onClick={this.onLogout}>退出</a>
36           </div>
37         </div>
38       </header>
39     )
40   }
41 }

退出后,清空 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 学习实践

标签:api   实践   ade   参考   资源   不能   ref   favicon   login   

原文地址:http://www.cnblogs.com/caihg/p/7111904.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!