理解
- React的一个插件库
- 专门用来实现一个SPA应用
- 基于React的项目都会使用到此库
React-router-web相关的API
< Link >
- 在React中靠酷游链接去切换组件
//案例
import { Link } from 'react-router-dom'
//路由跳转链接
<Link to="/about">About</Link>
< BrowserRouter >
import { BrowserRouter } from 'react-router-dom'
//把APP内的路由组件都交给一个路由管理
<BrowserRouter>
<App/>
</BrowserRouter>
< Route >
import { Route } from 'react-router-dom'
<Route path="/home" component={Home}/>
<Route path="/user/:username" component={User}/>
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
< NavLink>
- 一个特殊版本的 Link,当它与当前 URL 匹配时,为其渲染元素添加样式属性
import { NavLink } from 'react-router-dom'
// 实现导航链接高亮展示,显示默认颜色
<NavLink to="/about">About</NavLink>
//自定义选中样式
<NavLink
to="/about"
activeClassName="selected"
>About</NavLink>
//内联方式自定义选中样式
<NavLink
to="/about"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>About</NavLink>
//在样式中设置选中样式
.selected{
background-color:xxx !importent; //必须添加!importent 提高样式权限
color:xxx !importent;
}
< Switch>
- 渲染与该地址匹配的第一个子节点 或者
- 多个路由的话使用
import { Switch, Route } from 'react-router'
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/user" component={User}/>//匹配到第一个user路由组件,显示该组件
<Route path="/user" component={test}/>//不显示该组件
</Switch>
< Redirect >
- 渲染 将使导航到一个新的地址。这个新的地址会覆盖 history 栈中的当前地址
- 一般写在路由的最下方,当所有路由无法匹配时,跳转到Redirect指定的路由
<Redirect to="/home" />
嵌套路由
嵌套路由代码案例
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// 路由组件
const Main = () => <h2>Main</h2>;
const Sandwiches = () => <h2>Sandwiches</h2>;
const Tacos = ({ routes }) => (
<div>
<h2>Tacos</h2>
<ul>
<li>
<Link to="/tacos/bus">Bus</Link>
</li>
<li>
<Link to="/tacos/cart">Cart</Link>
</li>
</ul>
{routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
</div>
);
const Bus = () => <h3>Bus</h3>;
const Cart = () => <h3>Cart</h3>;
// 路由配置
const routes = [
{
path: "/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
];
//对路由组件容器的二次封装
const RouteWithSubRoutes = route => (
<Route
path={route.path}
render={props => (
<route.component {...props} routes={route.routes} />
)}
/>
);
const RouteConfigExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/tacos">Tacos</Link>
</li>
<li>
<Link to="/sandwiches">Sandwiches</Link>
</li>
</ul>
{routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
</div>
</Router>
);
export default RouteConfigExample;
路由传参
向路由组件传递params参数
- 路由链接(携带参数):< link to="/demo/tom/18"></ link >
- 注册路由(接收参数):< Route path="/demo/:name/:age" component={Test}></ Route >
- 接收参数:const {name ,age} = this.props.match.params
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const ParamsExample = () => (
<Router>
<div>
<h2>Accounts</h2>
<ul>
<li>
<Link to="/netflix">Netflix</Link>
</li>
<li>
<Link to="/zillow-group">Zillow Group</Link>
</li>
<li>
<Link to="/yahoo">Yahoo</Link>
</li>
<li>
<Link to="/modus-create">Modus Create</Link>
</li>
</ul>
<Route path="/:id" component={Child} />
</div>
</Router>
);
const Child = ({ match }) => (
<div>
<h3>ID: {match.params.id}</h3>
</div>
);
export default ParamsExample;
向路由组件传递search参数
- 路由链接(携带参数): < Link to="/demo?id=$ {info.id}&name=${info.name}" >{info.name}</ Link >
- 注册路由(无需接收参数): < Route path="/demo" component={Demo} />
- 接受参数:const {search} = this.props.location , const {id,name} = qs.parse(search.slice(1))
备注:路由组件接受参数由于是search参数:"?id=Netflix&name=Netflix"(urlencoded编码字符串),所以需要一个【querystring库】转化成"{id:‘Netflix’,name:‘Netflix’}"的格式
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
//不用安装,react脚手架已经下载好了,直接引入用
//将“?id=Netflix&name=Netflix”转换成一个对象{id:'Netflix',name:'Netflix'}的库
import qs from "querystring";
//举例子说明querystring库的使用
let obj= {name:'tom',age:18}
console.log(qs.stringify(obj)) //name=tom&age=18 urlencoded编码
let str = "name=tom&age=18"
console.log(qs.parse(str)) // {name:'tom',age:18}
export default class Test extends React.Component {
state = {
infos:[
{id:'Netflix',name:'Netflix'},
{id:'Zillow Group',name:'Zillow Group'}
]
}
render(){
const {infos} = this
return (
<Router>
<div>
<h2>Accounts</h2>
<ul>
{
infos.map((info) => {
return (
<li>
<Link to="/demo?id=${info.id}&name=${info.name}">{info.name}</Link>
</li>
)
})
}
</ul>
{/* search参数无需接受 */}
<Route path="/demo" component={Demo} />
</div>
</Router>
)
}
}
class Demo extends React.Component{
const {search} = this.props.location
const {id,name} = qs.parse(search.slice(1))
render(){
return (
<div>
<h3>ID: {id}</h3>
<h3>NAME: {name}</h3>
</div>
)
}
}
向路由组件传递state参数
- 路由链接(携带参数): < Link to={{pathname:’/demo’,state:{id:info.id,name:info.name}}} >{info.name}</ Link >
- 注册路由(无需接收参数): < Route path="/demo" component={Demo} />
- 接受参数: const {id,name} = this.props.location.sate
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
export default class Test extends React.Component {
state = {
infos:[
{id:'Netflix',name:'Netflix'},
{id:'Zillow Group',name:'Zillow Group'}
]
}
render(){
const {infos} = this
return (
<Router>
<div>
<h2>Accounts</h2>
<ul>
{
infos.map((info) => {
return (
<li>
<Link to={{pathname:'/demo',state:{id:info.id,name:info.name}}} >{info.name}</Link>
</li>
)
})
}
</ul>
{/* state参数无需接受 */}
<Route path="/demo" component={Demo} />
</div>
</Router>
)
}
}
class Demo extends React.Component{
//接收state参数
const {id,name} = this.props.location.sate
render(){
return (
<div>
<h3>ID: {id}</h3>
<h3>NAME: {name}</h3>
</div>
)
}
}
编程式路由导航
最常用的方法:replace()、push()、goback()、go()
注意只有路由组件才能使用以上编程式路由导航
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
export default class Test extends React.Component {
state = {
infos:[
{id:'Netflix',name:'Netflix'},
{id:'Zillow Group',name:'Zillow Group'}
]
}
clickKip = (id,name) => {
this.props.history.push(`/demo/${id}/${name}`) //无历史记录的跳转,可以回退
this.props.history.replace(`/demo/${id}/${name}`) //替换路由跳转
}
render(){
const {infos} = this
return (
<Router>
<div>
<h2>Accounts</h2>
<ul>
{
infos.map((info) => {
return (
<li>
<Link onClick={()=>this.clickKip(info.id,info.name)}>{info.name}</Link>
</li>
)
})
}
</ul>
{/* state参数无需接受 */}
<Route path="/demo" component={Demo} />
</div>
</Router>
)
}
}
class Demo extends React.Component{
//接收state参数
const {id,name} = this.props.match.params
render(){
return (
<div>
<h3>ID: {id}</h3>
<h3>NAME: {name}</h3>
</div>
)
}
}
withRouter
您可以通过 withRouter 高阶组件访问 history 对象的属性和最近的 的 match 。 当路由渲染时, withRouter 会将已经更新的 match , location 和 history 属性传递给被包裹的组件。
import React from "react";
import { withRouter } from "react-router-dom";
//一般组件
class Demo extends React.Component{
...
}
export default withRouter(Demo )
- withRouter的返回值是一个新组件;
- withRouter可以加工一般组件,让一般组件拥有路由组件所特有的API,可以向路由组件一样可以访问到match , location 和 history 属性,组件内也可以使用编程式导航;
BrowserRouter和HashRouter的区别
1.底层原理不一样
- BrowserRouter使用的是H5的history的API,不兼容IE9以及以下的版本
- HashRouter使用的是url的哈希值
2.url表现形式不一样
- BrowserRouter的路径上没有#,例如: http://localhost:3005/demo
- HashRouter的路径带#,例如: http://localhost:3005/#/demo
3.刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致state参数的丢失
4.备注:HashRouter可以用来解决一些路径错误相关的问题