https://reacttraining.com/react-router/web/guides/quick-start
提供 React Router4.0 路由的练习
一
1.React Router4.0 基本概念介绍
4.0版本已不需要路由配置,一切皆组件
react-router:基础路由包
提供了一些router的核心api,包括Router,Route,Switch等
react-router-dom:基于浏览器端的路由(包含react-router)
提供了BrowserRouter,HashRouter,Route,Link,NavLink
安装:npm install react-router-dom --save或yarn add react-router-dom
react-router-dom核心用法
HashRouter和BrowserRouter
HashRouter的写法eg.http://localhost:3000/#/admin/buttons
BrowserRouter的写法eg.http://localhost:3000/admin/buttons
Route:path、exact、component、render
exact属性代表精准匹配,必须path完全匹配才可以加载对应组件
eg1.
<Route path='/admin/ui/buttons' component={Buttons}/>
eg2.
<Route path='/admin' render={()=>
<Admin>
<Route path='/admin/home' component={Home} />
</Admin>
}/>
1
2
3
4
5
6
7
8
NavLink应用于菜单里作为菜单导航、Link超链接导航
eg1.
import {Link} from 'react-router-dom';
const Header=()=>{
<header>
<nav>
<li><Link to='/'>Home</Link></li>
<li><Link to='/about'>About</Link></li>
<li><Link to='/three'>Three</Link></li>
</nav>
</header>
}
eg2.
<Link to={{pathname:'/three/7'}}>Three #7</Link>
定义:<Route path="/three/:number"/>取值:this.props.match.params.number
同时在to属性中可以传递一个location对象,如:
{pathname:'/',search:' ',hash:'',key:'abc123',state:{}}
1
可以通过this.props.match.params.对象属性名取值
Switch[选择符合要求的Route,自上至下找到一个可以匹配的内容则不继续加载其他]
<Switch>
<Route path='/admin/ui/buttons' component={Buttons}/>
<Route path='/admin/ui/models' component={Models}/>
<Route path='/admin/ui/loading' component={Loading}/>
</Switch>
Redirect
路由重定向:<Redirect to="/admin/home">
2.React Router4.0 Demo介绍
4.0基本路由功能DEMO实现-混合组件化【将Route和Link放到同一个页面】
HashRouter将Link和Router进行包裹,其内部必须只能有一个子节点
通过Link组件的to属性设置路由地址;通过Route组件的path属性匹配路由地址,从而渲染对应component中的组件【注意:Route添加exact属性可以做到路径的精准匹配,否则/about既可以匹配/也可以匹配/about等路由地址】
实例代码:
Home.js用于显示整个页面内容
import React from 'react';
import {HashRouter,Route,Link,Switch} from 'react-router-dom'
import Main from './Main';
import About from './About';
import Topics from './Topics';
class Home extends React.Component{
render(){
return(
<HashRouter>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr></hr>
<Route path="/" exact={true} component={Main}></Route>
<Route path="/about" component={About}></Route>
<Route path="/topics" component={Topics}></Route>
</div>
</HashRouter>
);
}
}
export default Home;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Main.js组件
import React,{Component} from 'react';
class Main extends Component{
render(){
return(
<div>
this is Main.
</div>
);
}
}
export default Main;
1
2
3
4
5
6
7
8
9
10
11
Topic.js组件
import React,{Component} from 'react';
class Topics extends Component{
render(){
return(
<div>
this is Topics.
</div>
);
}
}
export default Topics;
1
2
3
4
5
6
7
8
9
10
11
About.js组件
import React,{Component} from 'react';
class About extends Component{
render(){
return(
<div>
this is About.
</div>
);
}
}
export default About;
4.0基本路由功能DEMO实现-配置化【将Route路由提取到一个单独的JS文件中】
配置化实现路由功能
创建Home.js内部写上ul->li->Link导航组件,并在想要显示对应路由内容的区域写上{this.props.children}即会加载调用Home.js组建时内部传递的信息
创建router.js,最外层用HashRouter包裹,第二级用Home组件包裹,内部写对应路由Route(path路由路径匹配、及component属性渲染的组件)
执行流程,index.js渲染Router组件时,由于最外层是HashRouter,内部是Home组件故加载Home组件内容,并通过{this.props.children}得到在调用Home组件时内部的信息。
嵌套路由
如想实现在Main组件中的嵌套路由,需要在Main组件中添加{this.props.children}从而渲染对应的内部信息,还需要添加Link组件以进行跳转
之后在router.js中对应调用该组件的Route组件中,删除component属性,添加render属性进行页面渲染,render属性内应是一个函数,返回Main组件(内部带有Route属性以进行路由渲染)
注意点:
调用Main组件的Route不能添加exact属性,因为如果添加exact属性,当点击内部组件路由到对应url时由于与外部Route的path不是完全匹配,故将不会显示
调用Main组件的Route内部render函数如果添加()=>{}则需要在函数体内写return,因为{}表示函数体,内部的函数将被执行,返回组件需要写return;如果不添加大括号则直接写返回的组件即可,ES6箭头函数默认箭头后面的内容是return的
调用Main组件的Route内部Main里的Route组件的path需要包含外部Route的path作为一级路由,如外部是/main内部需要是/main/xxx,如果不以外部Route作为一级路由则不会走外部的Route到内部Route内容
实例代码
/src/pages/router-demo/router2/router.js
import React from 'react';
import {HashRouter as Router,Route,Link}from 'react-router-dom';
import Main from './../router1/Main';
import About from './../router1/About';
import Topics from './../router1/Topics';
import Home from './Home';
class IRoute extends React.Component{
render(){
return(
<Router>
<Home>
<Route path="/main" render={()=>{
return(
<Main>
<Route path="/main/a" component={About}></Route>
</Main>
);}}></Route>
<Route path="/about" component={About}></Route>
<Route path="/topics" component={Topics}></Route>
</Home>
</Router>
);
}
}
export default IRoute;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/src/pages/router-demo/router2/Home.js
import React from 'react';
import {Link} from 'react-router-dom'
class Home extends React.Component{
render(){
return(
<div>
<ul>
<li>
<Link to="/main">Home1</Link>
</li>
<li>
<Link to="/about">About1</Link>
</li>
<li>
<Link to="/topics">Topics1</Link>
</li>
</ul>
<hr></hr>
{this.props.children}
</div>
);
}
}
export default Home;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/src/pages/router-demo/router2/Main.js
import React,{Component} from 'react';
import {Link} from 'react-router-dom';
class Main extends Component{
render(){
return(
<div>
this is Main.
<Link to="/main/a">To start a</Link>
<hr></hr>
{this.props.children}
</div>
);
}
}
export default Main;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
获取动态路由的值
在Main.js中设置跳转的路由链接
import React,{Component} from 'react';
import {Link} from 'react-router-dom';
class Main extends Component{
render(){
return(
<div>
this is Main.<br/>
<Link to="/main/test-id">嵌套路由1</Link><br/>
<Link to="/main/456">嵌套路由2</Link>
<hr></hr>
{this.props.children}
</div>
);
}
}
export default Main;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在router.js中添加动态路由即path:"/main/:value"用冒号定义的路由内容
import React from 'react';
import {HashRouter as Router,Route,Link,Switch}from 'react-router-dom';
import Main from './Main';
import About from './../router1/About';
import Topics from './../router1/Topics';
import Home from './Home';
import Info from './Info';
import NoMatch from './NoMatch';
class IRoute extends React.Component{
render(){
return(
<Router>
<Home>
<Switch>
<Route path="/main" render={()=>{
return(
<Main>
<Route path="/main/:value" component={Info}></Route>
</Main>
);}}></Route>
<Route path="/about" component={About}></Route>
<Route path="/topics" component={Topics}></Route>
<Route component={NoMatch}></Route>
</Switch>
</Home>
</Router>
);
}
}
export default IRoute;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在Info.js中获取定义的动态路由内容信息,通过{this.props.match.params.路由的名称}
import React,{Component} from 'react';
class Info extends Component{
render(){
return(
<div>
这里是测试动态路由功能
动态路由的值是{this.props.match.params.value}
</div>
);
}
}
export default Info;
1
2
3
4
5
6
7
8
9
10
11
12
添加默认路由
添加react-router-dom的Switch组件包裹Route组件用于设置自上自下只匹配一个路由
添加没有path属性的Route组件放置Switch组件内部的最后位置,作为默认路由
router.js如上代码,NoMatch.js如下所示:
import React from 'react';
class NoMatch extends React.Component{
render(){
return(
<div>
404 Not Found
</div>
);
}
}
export default NoMatch;
1
2
3
4
5
6
7
8
9
10
11
3.项目路由实战开发
由于用户访问项目时输入url需要有对应的输出,而作为整个文件输出时,一共有三种情况:登录、详情页、首页。故需要编写项目的入口文件router.js并在index.js中引入。【代码省略…】
router文件中定义使用路由的方式为HashRouter(即#/xxx/xxx的形式)
由于我们要访问完整路由时有登录页面、详情页面和首页,router文件需要定义根组件App,App.js内部什么都没有只有{this.props.children},主要用来存放子组件(即上述三个页面)。【如果没有用App进行包裹,即没有地方设置{this.props.children}显示路由的页面内容,即上述三个页面没法显示】
【总结结论:想利用Route显示组件信息,则必须有调动{this.props.children}显示其页面的组件】
有三个页面就需要有三个路由path分别为/login渲染登录组件、/admin渲染首页(其中里用render函数返回子路由Admin组件,并定义嵌套路由/admin/ui/buttons显示组件按钮;无path显示404页面,外层用Switch包裹保证只显示其中第一个匹配的Route)、和/order/detail渲染详情页。
//[/src/router.js]
import React,{Component} from 'react';
import {HashRouter,Route,Switch} from 'react-router-dom';
import App from './App';
import Login from './pages/login';
import Admin from './admin';
import Buttons from './pages/ui/buttons';
import NoMatch from './pages/nomatch';
class IRouter extends Component{
render(){
return(
<HashRouter>
<App>
<Route path="/login" component={Login}></Route>
<Route path="/admin" render={()=>{
return(
<Admin>
<Switch>
<Route path="/admin/ui/buttons" component={Buttons}></Route>
<Route component={NoMatch}></Route>
</Switch>
</Admin>
);
}}></Route>
<Route path="/order/detail" component={Login}></Route>
</App>
</HashRouter>
);
}
}
export default IRouter;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
将Admin组件中的content部分使用{this.props.children}显示在router.js中Route得到的页面
//[/src/admin.js]
import React from 'react';
import { Row, Col } from 'antd';
import Header from './components/Header';
import Footer from './components/Footer';
import NavLeft from './components/NavLeft';
import Home from './pages/home';
import './style/common.less'
class Admin extends React.Component{
render(){
return(
<Row className="container">
<Col span={6} className="nav-left">
<NavLeft/>
</Col>
<Col span={18} className="main">
<Header/>
<Row className="content">
{/* <Home></Home> */}
{this.props.children}
</Row>
<Footer/>
</Col>
</Row>
);
}
}
export default Admin;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
有Route就一定要有Link指定路由地址,我们在首页中通过左侧导航栏进行跳转,故需要在NavLeft组件中利用react-router-dom的NavLink设置路由地址,NavLink组件显示的内容为{item.title},to跳转的地址为{item.key}
//[/src/components/NavLeft/index.js]
import React from 'react';
import {Menu,Icon} from 'antd';
import MenuConfig from './../../config/menuConfig';
import './index.less';
import MenuItem from 'antd/lib/menu/MenuItem';
import {NavLink} from 'react-router-dom';
const SubMenu = Menu.SubMenu;
class NavLeft extends React.Component{
componentWillMount(){
const menuTreeNode = this.renderMenu(MenuConfig);
this.setState({
menuTreeNode
})
}
//菜单渲染
renderMenu=(data)=>{
return data.map((item,index)=>{
if(item.children){
return(
<SubMenu title={item.title} key={item.key}>
{this.renderMenu(item.children)}
</SubMenu>
)
}
return <Menu.Item title={item.title} key={item.key}>
<NavLink to={item.key}>{item.title}</NavLink>
</Menu.Item>
})
}
render(){
return(
<div>
<div className="logo">
<img src="/assets/logo-ant.svg" alt=""></img>
<h1>Imooc MS</h1>
</div>
<Menu theme="dark">
{this.state.menuTreeNode}
</Menu>
</div>
);
}
}
export default NavLeft;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
在router.js中可以看到如果匹配的是/admin/ui/buttons则将Button组件渲染到Admin组件的content中;如没有写对应的路由匹配则将404页面渲染到Admin组件的content中,对应代码如下
//[/src/pages/ui/buttons.js]
import React,{Component} from 'react';
class Buttons extends Component{
render(){
return(
<div>
This is Buttons Page.
</div>
)
}
}
export default Buttons;
//[/src/pages/nomatch/index.js]
import React from 'react';
class NoMatch extends React.Component{
render(){
return(
<div style={{textAlign:'center',fontSize:'24'}}>
404 Not Found!!!
</div>
);
}
}
export default NoMatch;
---------------------
作者:汪喆_Jack
来源:优快云
原文:https://blog.youkuaiyun.com/qq_34829447/article/details/81916545
版权声明:本文为博主原创文章,转载请附上博文链接!