和Vue有vue-router来管理路由一样,React中也有一个用于管理路由的react-router,基本的使用也是差不多的,下面通过一个项目的简单搭建来学习基本的使用方法
搭建项目
首先使用create-react-app脚手架搭建一个项目,搭建完成后将react-router,react-router-dom安装到本地项目
create-react-app mydemo
cnpm i react-router --save
cnpm i react-router-dom --save
接下来我们将src中的文件清空,自己重新来写一下
编写基本的路由
首先新建index.js,导入我们需要的各种内容
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router,Route,Link } from 'react-router-dom'
这里是要在web下运行,导入了BrowserRouter并命名为Router,接下里写一个组件来render到页面上
class AppRouter extends React.Component{
render(){
return (
<div>here is AppRouter</div>
)
}
}
ReactDOM.render(<AppRouter />, document.getElementById('root'))
此时运行npm run start我们就能看到页面上的here is AppRouter了,接下来就是编写路由和路由对应的组件了
在react-router中,我们通过从react-router-dom中拿到的Link来做跳转,Route来做对应匹配哪个组件显示,这与vue-router中的router-link和router-view类似,不同的是,vue-router中的router-link和router-view可以和其他标签放的位置一样,而Link和Route却只能放在Router中,否则就会报错
正确的写法如下
class AppRouter extends React.Component{
render(){
return(
<Router>
<li>
<Link to="/">HOME</Link>
</li>
<li>
<Link to="/about">ABOUT</Link>
</li>
<li>
<Link to="/topics">TOPICS</Link>
</li>
{/* exact:精确匹配,为布尔值,默认为false,即不做精确匹配 */}
{/* 需要完全匹配的时候才使用exact */}
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/topics" component={Topics} />
</Router>
)
}
}
然后我们编写相应的组件
class Home extends React.Component{
render(){
return(
<div>this is Home page</div>
)
}
}
class About extends React.Component{
render(){
return (
<div>this is About page</div>
)
}
}
class Topics extends React.Component{
render(){
return (
<div>this is Topics page</div>
)
}
}
到这里就可以在页面上显示对应的内容并且做跳转了
到这里就算基本完成了,我们回到上面说的,如果我们不将Link和Route放在Router中,会发生什么呢
class AppRouter extends React.Component{
render(){
return(
// 将Router替换成div
<div>
<li>
<Link to="/">HOME</Link>
</li>
<li>
<Link to="/about">ABOUT</Link>
</li>
<li>
<Link to="/topics">TOPICS</Link>
</li>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/topics" component={Topics} />
</div>
)
}
}
就会出现下面的报错
解决这个问题后,我们将Link和Route分别放在两个不同的组件,为了减少多余的父组件,这里使用fragments的短语法<></>
class AppRouter extends React.Component{
render(){
return(
<Router>
<RouterLink />
<RouterShow />
</Router>
)
}
}
class RouterLink extends React.Component{
render(){
return(
<>
<li>
<Link to="/">HOME</Link>
</li>
<li>
<Link to="/about">ABOUT</Link>
</li>
<li>
<Link to="/topics">TOPICS</Link>
</li>
</>
)
}
}
class RouterShow extends React.Component{
render(){
return(
<>
{/* exact:精确匹配 */}
{/* 需要完全匹配的时候才使用exact */}
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</>
)
}
}
Route的属性
接下来看看上面Route使用的两个属性exact和path,在vscode中可以直接按住ctrl点击Route标签看看这个组件的源代码
可以看到以下内容
export interface RouteProps {
location?: H.Location;
component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
render?: ((props: RouteComponentProps<any>) => React.ReactNode);
children?: ((props: RouteChildrenProps<any>) => React.ReactNode) | React.ReactNode;
path?: string | string[];
exact?: boolean;
sensitive?: boolean;
strict?: boolean;
}
export class Route<T extends RouteProps = RouteProps> extends React.Component<T, any> { }
exact上面已经在代码的注释里面看到了,它是一个布尔值,告诉我们是否精确匹配,我们看到上面代码里面,About组件对应的路由是没用精确匹配的,所以下面的路由也可以显示About组件
而一旦修改为精确匹配
我们发现它已经匹配不到About组件了,这就是exact
说说path,显然path就是用来写路由,而componentj就是路由对应的组件,我们看到,在上面的代码中path是可以使用字符串和字符串数组的,也即是说,同一个组件,可以匹配多个路由,只要使用数组的形式来写就可以
<Route path={["/about",'/about1']} component={About} />
发现/about和/about1都可以显示About组件