我們通過一個用戶管理實例來學習react-router-dom
這個實例包括9個小組件
App.js 引入組件
Home.js 首頁組件
User.js 用戶管理組件
- UserList.js 用戶列表組件
- UserAdd.js 用戶添加組件
- UserDetail.js 用戶詳情組件
Profile.js 個人中心組件
Login.js 用戶登錄組件
Protected.js 處理登錄的組件(我們模擬登錄的)
我們先建立一個App組件,作為我們項目引入的組件
import React, {Component} from 'react';
//Router 容器,它是用來包裹路由規則的
//Route 是路由規則
//BrowserRouter基於h5的。兼容性不好
//引入react-router-demo
import {HashRouter as Router, Route,Link,NavLink,Switch} from 'react-router-dom';
//引入我們需要的組件
import Home from "./Home";
import User from "./User";
import Profile from "./Profile";
import Login from "./Login";
import Protected from './Protected'
//定義一個App組件
export default class App extends Component {
render() {
//定義一個我們選中的狀態
let activeStyle={color:'red'}
return (
<Router>
<div className="container">
<nav className='nav navbar-default'>
<div className="container-fluid">
<a className="navbar-brand">用戶管理</a>
</div>
<ul className="nav">
<li className='navbar-nav'><NavLink exact activeStyle={activeStyle} to="/">首頁</NavLink></li>
<li className='navbar-nav'><NavLink activeStyle={activeStyle} to="/user">用戶管理</NavLink></li>
<li className='navbar-nav'><NavLink activeStyle={activeStyle} to="/profile">個人中心</NavLink></li>
</ul>
</nav>
<div>
{/*Switch是匹配*/}
{/*exact 我們匹配/斜杠時候,就匹配第一個*/}
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/user" component={User}/>
<Protected path="/profile" component={Profile}/>
<Route path="/login" component={Login}/>
</Switch>
</div>
</div>
</Router>
)
}
}
App組件使我們引入的組件,在這個組件里面,我們需要注意到最外層的Router
這個是路由容器,我們路由規則Route需要包裹在日期里面
Route包含了兩個屬性,path 和 component
path指向的路由路徑,component指向的是要跳轉的組件
我們路由導航,一般是Link和NavLink兩個
這兩個功能一樣,都是路由跳轉,但是NavLink有一個屬性用來顯示跳轉選中的樣式,activeStyle屬性,寫顯示高亮樣式的,接收一個對象{}
在我們路由導航有一個to屬性
to屬性是我們路由的要跳轉的路徑
下面是User.js 組件,主要包含兩個路由NavLink和Route,和上面一個意思,切換兩個組件NavLink和Route
import React, {Component} from 'react'
import {Link,Route,NavLink} from 'react-router-dom'
import UsersList from './UsersList'
import UsersAdd from './UsersAdd'
import UserDetail from "./UserDetail";
export default class User extends Component {
render() {
let activeStyle={color:'red'}
return (
<div className='row'>
<div className="col-sm-3">
<nav>
<ul className="nav nav-stacked">
<li><NavLink activeStyle={activeStyle} to="/user/list">用戶列表</NavLink></li>
<li><NavLink activeStyle={activeStyle} to="/user/add">添加用戶</NavLink></li>
</ul>
</nav>
</div>
<div className="col-sm-9">
<Route path="/user/list" component={UsersList}></Route>
<Route path="/user/add" component={UsersAdd}></Route>
<Route path="/user/detail/:id" component={UserDetail}></Route>
</div>
</div>
)
}
}
- UserAdd.js 用戶添加組件
import React, {Component} from 'react'
export default class UsersAdd extends Component {
handleSubmit=()=>{
let username=this.refs.username.value;
let password=this.refs.password.value;
let user={username,password,id:Date.now()};
let users=JSON.parse(localStorage.getItem('USERS')||"[]");
users.push(user);
localStorage.setItem('USERS',JSON.stringify(users));
this.props.history.push('/user/list')
}
render() {
/*
* history 用來跳轉頁面
* location.pathname 用來存放當前路徑
* match代表匹配的結果
*
* */
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="username" className="control-label">
用戶名
</label>
<input type="text" className="form-control" ref="username" placeholder="用戶名"/>
</div>
<div className="form-group">
<label htmlFor="username" className="control-label">
密碼
</label>
<input type="password" className="form-control" ref="password" placeholder="密碼"/>
</div>
<div className="form-group">
<input type="submit" className="btn btn-danger" />
</div>
</form>
)
}
}
我們將用戶添進去的數據,在頁面緩存,方便我們用戶列表頁渲染
localStorage.setItem('USERS',JSON.stringify(users));
緩存完成后跳轉到列表詳情頁面userList
this.props.history.push('/user/list')
- UserList.js 用戶列表組件
import React, {Component} from 'react'
import {Link} from 'react-router-dom'
export default class UsersList extends Component {
constructor(){
super();
this.state={users:[]}
}
componentWillMount(){
let users = JSON.parse(localStorage.getItem('USERS') || "[]");
this.setState({users});
}
render(){
return (
<ul className="list-group">
{
this.state.users.map((user,index)=>(
<li key={index} className="list-group-item">
<span>用戶名:</span>
<Link to={`/user/detail/${user.id}`}>{user.username}</Link>
<span className="btn btn-danger" onClick={()=>{
let users=this.state.users.filter(item=>item.id!=user.id)
this.setState({users});
}}>刪除</span>
</li>
))
}
</ul>
)
}
}
componentWillMount()是組件掛載完成后的組件周期函數
在這個鈎子函數里面,我們去userAdd存儲的USERS數據,然后渲染到頁面上去
<Link to={`/user/detail/${user.id}`}>{user.username}</Link>
這里面我們跳轉到個人信息詳情里面,把每個人的用戶id帶上
然后我們用戶詳情頁面UserDetail.js 組件
import React, {Component} from 'react'
export default class UserDetail extends Component {
render() {
// let user=this.props.location.state.user
let users = JSON.parse(localStorage.getItem('USERS')||"[]");
let id = this.props.match.params.id;
let user = users.find(item=>item.id == id);
return (
<table className="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>用戶名</th>
<th>密碼</th>
</tr>
</thead>
<tbody>
<tr>
<td>{user.id}</td>
<td>{user.username}</td>
<td>{user.password}</td>
</tr>
</tbody>
</table>
)
}
}
let id = this.props.match.params.id;
let user = users.find(item=>item.id == id);
通過match里面獲取到路由帶過來的id
然后判斷users里面id相同的那一項
然后渲染到頁面上去
,然后我們判斷登錄,如果沒有登錄,就去登錄,登錄后才能看用戶管理
import React from 'react'; import {Route, Redirect} from 'react-router-dom'; //函數組件 //把屬性對象中的Component屬性取出來賦給comp,把其它屬性取出來賦給other對象 //再把other對象的全部屬性取出來賦給Route // component=組件 // render函數 當路由匹配的時候,渲染的是render方法的返回值 export default function ({component: _comp, ...rest}) { return <Route {...rest} render={ props => localStorage.getItem('login') ? <_comp/> : <Redirect to={{pathname: '/login', state: {from: props.location.pathname}}}/> }/> return null; }
如果沒有登錄,我們就進入登錄組件,其實我們模擬登錄就是設置了一個緩存login為true,模擬權限,真實項目中,我們通過后台接口來限制,路由跳轉
import React, {Component} from 'react';
export default class Login extends Component {
handleClick = ()=>{
localStorage.setItem('login','true');
console.log(this.props);
this.props.history.push(this.props.location.state.from);
}
render() {
return (
<div>
<button
onClick={this.handleClick}
className="btn btn-primary">登錄
</button>
</div>
)
}
}
后面,我們首頁Hone和Profile兩個組件,基本就是展示個人信息的,就是渲染,所以我就沒有必要寫了!
總體完成,路由嵌套路由,然后通過路由參數分辨路由不同的信息
