1. 安装
yarn add react-router@5 react-router-dom@5
2. 基础使用和一些案例
2.1 基础使用
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import Home from './components/Home';
import Hello from './components/Hello';
import List from './components/List';
function App() {
return (
<Router>
<div>
<Link to='/'>home</Link>
<Link to='/hello'>hello</Link>
<Link to='/list'>list</Link>
</div>
<Switch>
<Route path='/' exact component={Home}></Route>
<Route path='/hello'>
<Hello/>
</Route>
<Route path='/list'>
<List/>
</Route>
</Switch>
</Router>
);
}
export default App;
- Link类似于a标签,点击进行跳转
- v5默认的路由匹配规则默认是不开启精确匹配的,而且可以同时匹配多个。 通过exact属性给Route添加精确匹配,被Switch包裹的route只会渲染其中的一个
下面的代码在访问 /hello的时候会同时渲染home和hello组件,解决办法就是给home的route添加exact或者在外面包上一层Switch
<Route path='/' component={Home}></Route>
<Route path='/hello'>
<Hello/>
</Route>
<Route path='/list'>
<List/>
</Route>
2.2 Route中组件的渲染方式
- 通过element属性渲染
- 通过render渲染
- 通过children渲染
// 通过component渲染
function App() {
return (
<Router>
<Switch>
<Route path='/home' component={Home}></Route>
</Switch>
</Router>
);
}
// 通过render渲染
function App() {
return (
<Router>
<Switch>
<Route path='/home' exact render={(props)=>{
console.log(props); //{history...,location...,match...}
return <Home/>
}}></Route>
</Switch>
</Router>
);
}
// 通过children渲染
function App() {
return (
<Router>
<Switch>
<Route path='/home' exact children={(props)=>{
console.log(props); //{history...,location...,match...}
return <Home/>
}}></Route>
</Switch>
</Router>
);
}
区别是element是直接渲染组件,而render和children是通过函数的方式渲染,可以获取路由的参数,包含history、location和match对象。一般情况下这三个只使用一个即可,如果同时使用多个优先级是:element > render > children 。
2.3 路由嵌套
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/home' component={Home}></Route>
<Route path='/article'>
<div>文章首页</div>
<Route path='/article/publish' component={Puhlish}></Route>
<Route path='/article/read' component={Read}></Route>
</Route>
</Switch>
</Router>
);
}
由于Route本身也是react元素,可以进一步将子路由封装成组件或者函数,将每个模块的路由单独封装,更有利于重新组合和复用
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/home' component={Home}></Route>
<Route path='/article'>
<Articles />
</Route>
</Switch>
</Router>
);
}
function Articles() {
return <div>
<div>文章首页</div>
<Route path='/article/publish' component={Puhlish}></Route>
<Route path='/article/read' component={Read}></Route>
</div>
}
2.4 Redirect重定向
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/login' component={Login}></Route>
<Route path='/home' component={Home}>
<Redirect to='/login' />
</Route>
</Switch>
</Router>
);
}
function Home() {
return 'home'
}
function Login() {
return 'login'
}
2.5 使用withRouter获取url参数
widthRoute是一个高阶组件,会给组件的属性上添加history,location,和match三个对象。
- history 保存用户访问网页的历史记录,提供go、replace、push等方法进行url的切换和跳转
- location 保存当文档所在的位置信息,其中包含pathname、search(query的参数)、hash等
- match 包含路由的匹配规则,如匹配的url和动态路由的参数(/:id=5)
import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/home/:id/:name' component={Home}></Route>
</Switch>
</Router>
);
}
const Home = withRouter(function(props){
console.log(props);
return 'home'
});
访问/home/123/jack?u_id=555,打印结果如下:
- 动态路由的参数通过match对象获取
- url中query的参数通过history和search获取,不过要自己封装方法提取
2.6 自定义Link组件
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
function App() {
return (
<Router>
<MyLink to='/home'>首页</MyLink>
<Switch>
<Route path='/home' component={Home}></Route>
<Route path='/login' component={Login}></Route>
</Switch>
</Router>
);
}
function MyLink(props = {}) {
const { to } = props;
return <Link to={to}>{props.children}</Link>
}
function Home() {
return 'home'
}
function Login() {
return 'login'
}
2.7 404页面
使用/*匹配所有页面,该路由必须要放到最下面,且最外层使用Switch包裹
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/' exact component={Home}></Route>
<Route path='/login' component={Login}></Route>
<Route path='/*' component={NoMatch}></Route>
</Switch>
</Router>
);
}
function Home() {
return 'home'
}
function Login() {
return 'login'
}
function NoMatch(){
return '404'
}
2.8 以数据配置的方式渲染路由
以数据的方式渲染路由,更容易拆分和耦合,减少代码重复,降低代码量。
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const routes = [
{ path: '/home',
component: Home,
id:"home",
},
{
path: '/login',
component: Login,
id:'login',
}
];
function App() {
return (
<Router>
<Switch>
{routes.map((route, index)=> <Route {...route} key={route.id || index}/>)}
</Switch>
</Router>
);
}
function Home() {
return 'home'
}
function Login() {
return 'login'
}
3. v5中的hooks
v5中也新增了一些hooks,主要是用来代替withRouter的。
3.1 useParams()
useParams用来获取动态路由所匹配到的参数,代替withRouter中的math.params
import { BrowserRouter as Router, Route, useParams } from 'react-router-dom';
const Home = function (props) {
const { id, name } = useParams();
return <div>
<span>home</span>
<span>id:{id}</span>
<span>name:{name}</span>
</div>
};
3.2 useHistory()、useLocation()、useRouteMatch()
useHistory()、useLocation()、useRouteMatch()分用来获取history、location、match对象
import { BrowserRouter as Router, Route, Switch, useHistory, useLocation, useRouteMatch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path='/home/:id/:name' component={Home}></Route>
</Switch>
</Router>
);
}
const Home = function (props) {
console.log(useHistory())
console.log(useLocation())
console.log(useRouteMatch())
return <div>
<span>home</span>
</div>
};
3. 总结
- 给Route添加exact属性开启精确匹配。
- 被Switch包裹的组件只渲染一个。
- 使用 /* 匹配所有路径。
- Route渲染组件的的方式有element、render、children,render和children是通过函数渲染可以获取路由的参数。
- 将每个模块的路由单独抽离封装,再以数据驱动的方式渲染Route更有利于路由的重组和耦合,提高代码复用。
- 使用withRoute()方法获取history、location、match对象。其中包含路由动态匹配的参数以及url中的query参数。
- 使用useParams()、useHistory()、useLocation()、useRouteMacth()代替withRouter。