1.搭建最简单的路由环境 #

  1. 生成项目

    create-react-app react-router-4-lesson
    cd react-router-4-lesson
    yarn start
    
  2. 安装react-router-dom

    npm install react-router-dom -S
    
  3. 配置基本路由

src/App.js

import React from 'react'
import {
    BrowserRouter as Router,
    Route,
    Link
} from 'react-router-dom'

const Home = () => (
    <div>
        <h2>首页</h2>
    </div>
)

const User = () => (
    <div>
        <h2>用户管理</h2>
    </div>
)

const Profile = () => (
    <div>
        <h3>个人设置</h3>
    </div>
)

const App = () => (
    <Router>
        <div>
            <ul>
                <li><Link to="/">主页</Link></li>
                <li><Link to="/user">用户管理</Link></li>
                <li><Link to="/profile">个人设置</Link></li>
            </ul>

            <hr/>

            <Route exact path="/" component={Home}/>
            <Route path="/user" component={User}/>
            <Route path="/profile" component={Profile}/>
        </div>
    </Router>
)
export default App

2. 引入bootstrap #

  1. 安装bootstrap
    npm install bootstrap -S
    
  2. 引入bootstrap
    import 'bootstrap/dist/css/bootstrap.css';
    
  3. 使用bootstrap src/App.js
    <div className="navbar navbar-default">     <div className="container-fluid">
         <div className="navbar-header">
             <div className="navbar-brand">
                 <Link to="/">学生管理系统</Link>
             </div>
         </div>
         <div>
             <ul className="nav navbar-nav">
                 <li><Link to="/">首页</Link></li>
                 <li><Link to="/user">用户管理</Link></li>
                 <li><Link to="/profile">个人设置</Link></li>
             </ul>
         </div>
     </div>
    </div>
    <div className="container">
    <Route exact path="/" component={Home}/>
    <Route path="/user" component={User}/>
    <Route path="/profile" component={Profile}/>
    </div>
    

    3. 实现二级路由 #

  4. 先把Home、User、Profile都独立到各自不同的组件文件中去

  5. 实现用户管理中的二级路由 src/User.js

    import React from 'react';
    import {Route,Link} from 'react-router-dom';
    import UserList from './UserList';
    import UserAdd from './UserAdd';
    const User = () => (
     <div className="row">
         <div className="col-md-2">
             <ul className="nav nav-pills nav-stacked">
                 <li role="presentation"><Link to="/user/list">用户列表</Link></li>
                 <li role="presentation"><Link to="/user/add">增加用户</Link></li>
             </ul>
         </div>
         <div className="col-md-10">
             <Route path={`/user/list`} component={UserList}/>
             <Route path={`/user/add`} component={UserAdd}/>
         </div>
     </div>
    )
    export default User
    

4. 获取路径参数 #

  1. 添加一个用户详情页的路由

src/User.js

import React from 'react';
import {Route,Link} from 'react-router-dom';
import UserList from './UserList';
import UserAdd from './UserAdd';
import UserDetail from './UserDetail';
 const User = () => (
     <div className="row">
         <div className="col-md-2">
         <div className="col-md-10">
             <Route path={`/user/list`} component={UserList}/>
             <Route path={`/user/add`} component={UserAdd}/>
             <Route path={`/user/detail/:id`} component={UserDetail}/>
         </div>
     </div>
 )

src/UserDetail.js

import React from 'react'
export default class UserDetail extends React.Component{
     render(){
         let {match} = this.props;
         return (
             <div className="panel panel-default">
                 <div className="panel-body">
                     ID:{match.params.id}
                     姓名:
                 </div>
             </div>
         )
     }
}

UserList.js

import React from 'react';
import {Link} from 'react-router-dom';
const UserList = () => (
    <ul className="list-group">
        <li className="list-group-item">
            <Link to="/user/detail/1">张三</Link>
        </li>
        <li className="list-group-item">
            <Link to="/user/detail/2">李四</Link>
        </li>
    </ul>
)
export default UserList

5. switch只显示一个组件 #

src/App.js

import {Switch} from 'react-router-dom'
<Switch>
 <Route exact path="/" component={Home}/>
 <Route path="/user" component={User}/>
 <Route path="/profile" component={Profile}/>
</Switch>

6. 另一种渲染组件的方式 #

src/App.js

<Router>
       <div>
           <div className="navbar navbar-inverse">
               <div className="container-fluid">
                   <div className="navbar-header">
                       <div className="navbar-brand">
                           <Link to="/">学生管理系统</Link>
                       </div>
                   </div>
                   <div>
                       <ul className="nav navbar-nav">
                           <li><Link to="/zhufengpeixun">品牌</Link></li>
                       </ul>
                   </div>
               </div>
           </div>
           <div className="container">
               <Switch>
                 <Route path="/:name" render={({match})=>(<div>{match.params.name}</div>)}/>
               </Switch>
           </div>
       </div>
   </Router>

7. 实现登录和退出功能 #

src/App.js

import React from 'react'
import 'bootstrap/dist/css/bootstrap.css';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch
} from 'react-router-dom'

import Home from './Home';
import User from './User';
import Profile from './Profile';
import PrivateRoute from './PrivateRoute';
import Login from './Login';
const App = () => (
    <Router>
        <div>
            <div className="navbar navbar-inverse">
                <div className="container-fluid">
                    <div className="navbar-header">
                        <div className="navbar-brand">
                            <Link to="/">学生管理系统</Link>
                        </div>
                    </div>
                    <div>
                        <ul className="nav navbar-nav">
                            <li><Link to="/">首页</Link></li>
                            <li><Link to="/user">用户管理</Link></li>
                            <li><Link to="/profile">个人设置</Link></li>
                            <li><Link to="/zhufengpeixun">品牌</Link></li>
                        </ul>
                        <ul className="nav navbar-nav navbar-right">
                            <li><Route path="/" render={({history}) => (<a onClick={() => {localStorage.clear();history.push('/');}}>退出</a>)}/></li>
                        </ul>
                    </div>
                </div>
            </div>
            <div className="container">
                <Switch>
                    <Route exact path="/" component={Home}/>
                    <Route path="/user" component={User}/>
                    <PrivateRoute path="/profile" component={Profile}/>
                    <Route path="/login" component={Login}/>
                    <Route path="/:name" render={({match}) => (<div>{match.params.name}</div>)}/>
                </Switch>
            </div>
        </div>
    </Router>
)
export default App

src/PrivateRoute.js

import React from 'react'
import {Route,Redirect} from 'react-router-dom'
const PrivateRoute = ({component: Component,...rest}) => (
    <Route {...rest} render={props => (
        localStorage.getItem('login') ? <Component/> : <Redirect to={{
            pathname: '/login',
            state: {from: props.location}
        }}/>
    )}>
    </Route>
)export default  PrivateRoute

src/Login.js

import React from 'react';
import {withRouter} from 'react-router-dom';
class Login extends React.Component{
    render(){
        let {history,location} = this.props;
        return (
            <div>
                <button className="btn btn-primary" onClick={()=>{
                    localStorage.setItem('login','true');
                    history.push(location.state.from.pathname);
                }}>登录</button>
            </div>
        )
    }
}
export default  withRouter(Login)

8. 实现选中菜单的高亮显示 #

src/MenuLink.js

import React from 'react'
import {Route, Link} from 'react-router-dom'
const MenuLink = ({ label, to, activeOnlyWhenExact }) => (
    <Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
        <li className={match ? 'active' : ''}>
            <Link to={to}>{label}</Link>
        </li>
    )}/>
)
export default MenuLink

src/App.js

 <MenuLink activeOnlyWhenExact={true} to="/" label="首页"/>
 <MenuLink activeOnlyWhenExact={true} to="/user" label="用户管理"/>
 <MenuLink activeOnlyWhenExact={true} to="/profile" label="个人设置"/>

9. 切换路由的时候进行提示 #

src/UserAdd.js

import React from 'react';
import {Prompt} from 'react-router-dom';
export default class UserAdd extends React.Component {
    constructor(props) {
        super(props);
        this.state = {blocking: false};
    }

    handleChange = (event) => {
        this.setState({
            blocking: event.target.value && event.target.value.length > 0
        });
    }
    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({
            blocking: false
        }, () => {
            this.props.history.push('/user/list');
        });

    }

    render() {
        return (
            <div>
                <Prompt
                    when={this.state.blocking}
                    message={location => (
                        `你确定你要去 ${location.pathname} 吗?`
                    )}
                />
                <form onSubmit={this.handleSubmit}>
                    <div className="form-group">
                        <label htmlFor="name">姓名</label>
                        <input ref={(ref) => this.name = ref} type="text" onChange={this.handleChange}
                               className="form-control"/>
                    </div>
                    <div className="form-group">
                        <button type="submit" className="btn btn-primary">提交</button>
                    </div>
                </form>
            </div>
        )
    }
}

10. 404页面 #

src/App.js

<Route component={NoMatch}/>

src/NoMatch.js

import React from 'react'
const  NoMatch = () => (
    <div>
        <h3>此路径不存在</h3>
    </div>
)
export default  NoMatch

参考代码 #