react router
目录
- 前言
- 核心
- 1、内置的组件
- 2、内置的路由器组件
- 3、History 对象
- 4、Location 对象
- 5、react router 的安装包
- 一、React-Router v1
- 1、一些概念
- (1)、Router、Route 对象
- (2)、history 对象
- (3)、location 对象
- 2、组件
- (1)、Router 和 Route 组件
- (2)、Redirect 组件
- (3)、Link 组件
- 3、特性
- (1)、支持 mixin
- 4、API
- (1)、生命周期
- 5、一般的使用案例
- 二、React-Router v2
- 1、特性
- (1)、用 browserHistory 代替 createBrowserHistory
- (2)、用 render 属性代替 RoutingContext 属性
- (3)、弃用 mixin
- 2、一般的使用案例
- 三、React-Router v3
- 1、一般的使用案例
- 四、React-Router v4
- 1、拆包
- 2、组件
- (1)、<Route> 组件
- (2)、<Router> 组件
- (3)、<Link> 组件
- (4)、<NavLink> 组件
- (5)、<Switch> 组件
- (6)、组件的嵌套
- 3、API
- (1)、生命周期
- (2)、history 对象
- (3)、props 对象
- (4)、 location 对象
- ①、location.query
- ②、location.action
- 4、一般的使用案例
- 五、React-Router v5
- 1、组件
- (1)、<Route> 组件的变化
- (2)、内置的路由器组件的引入方式变了
- 2、API
- (1)、新增一些 hooks API
- (2)、弃用 2 个 react 的生命周期方法
- (3)、withRouter 函数
- 3、一般的使用案例
- 六、React-Router v6
- 1、组件
- (1)、<Routes> 替换 <Swicth>
- (2)、<Outlet> 组件
- (3)、<Navigate> 替换 <Redirect>
- 2、特性
- (1)、<Route> 组件的特性变更
- ①、使用 element 属性替换原来的 component 属性
- ②、新增 caseSensitive 属性
- ③、弃用 exact 属性
- (2)、<NavLink/> 特性变更
- 3、API
- (1)、hooks
- 4、一般的使用案例
前言
React Router 的官网(英文)
React Router 的官方提供的使用案例
react-router 的历代版本更迭
由于 React-Router 多个版本使用的方式有较大的区别,所以本文主要总结下各个版本的特性与用法。
一般来说,router 指的是 URL 和 网页之间的映射。
核心
这个“核心”指的是:到目前为止仍是核心的内容。
1、内置的组件
<Route>
组件:一条路由。<Router>
组件:可以用来包裹多个 Route 组件。<Link>
组件:跳转连接。<Redirect>
组件:路由重定向。
2、内置的路由器组件
<Route> 组件是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由器组件:
<BrowserRouter>
组件:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步。<HashRouter>
组件:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步。<MemoryRouter>
组件:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写)。<NativeRouter>
组件:为使用 React Native 提供路由支持。<StaticRouter>
组件:从不会改变地址。
3、History 对象
浏览器没有直接提供监听URL改变(push、pop、replace)的接口,因此 react-router 对原生的 history 对线进行了包装,提供了监听URL改变的API。
使用 react-router 时不需操作History对象(Routes 组件会进行操作)。
三种不同的 History 路由器:BrowerHistory、HashHistory 和 createMemoryHistory。
browserHistory
使用的是 HTML5 History API。- browserHistory 需要在服务器端进行额外配置来提供 URL。
- 它通常是现代网页的首选解决方案。
hashHistory
使用 URL 哈希以及查询键来跟踪状态。- URL 中有
#
。 - 刷新页面后为导致 URL 的参数丢失。
- URL 中有
createMemoryHistory
:实现服务器渲染的方式。
关于 react router 的 History,可以参考官方给出的这篇文档,如果要了解他的历史变更可以看这篇文档
4、Location 对象
react-router 对 window.location 进行包装后,提供了一个形式简洁的 Location 对象。
Location 对象的属性:
- pathname:主机名之后的URL地址
- search:查询参数
- hash:哈希值,用于确定页面滚动的具体位置
- state:对于 window.history.state 的包装
- key:唯一标识。可以据此来实现基于 Location 的滚动管理或数据缓存。
5、react router 的安装包
react-router
:路由核心库。不包含对 DOM 的操作。react-router-dom
:适用于浏览器环境的再次封装。- 包含了 react-router 的核心部分。
- 比 react-router 多出了 <Link> <BrowserRouter> 这样的 DOM 类组件。
react-router-native
:适用于 react-native 环境。- 包含了 react-router 的核心部分。
react-router-config
:静态路由配置助手。
一、React-Router v1
v1.0.0 官方
1、一些概念
词汇表
(1)、Router、Route 对象
Route:一条路由。
Router:一个可以包含多条 Route 的路由对象,用来管理路由。
(2)、history 对象
- 它提供了很多有用的方法可以在路由系统中使用,比如:history.replaceState,用于替换当前的 URL。
- React-Router 里的 history 对象与 window.history 不同,前者是通过 history 包里面的 create*History 方法创建的对象,后者是浏览器原生的 history 对象,不要弄混。
- history.listen:用于需要在一段时间内更新 UI 的有状态环境(例如 Web 浏览器)。此方法立即调用其 listener 参数一次并返回一个必须调用以停止侦听更改的函数。
- history.match:是一个纯异步函数,不会更新历史的内部状态。这使其成为必须同时处理许多请求的服务器端环境的理想选择。
(3)、location 对象
- 它可以简单的认为是 URL 的对象形式表示。
- location.state 的 state 对象与 HTML5 history.pushState API 中的 state 对象一样。
- 每个 URL 都会对应一个 state 对象,你可以在对象里存储数据,但这个数据却不会出现在 URL 中。实际上,数据被存在了 sessionStorage 中。
其他的概念请查阅官方提供的 词汇表。
2、组件
(1)、Router 和 Route 组件
在 React-Router v1 中 Router 和 Route 组件的意义:
- Route 是一个组件,它的 path 属性表示路由组件所对应的路径,可以是绝对或相对路径,相对路径可继承。
- Router 是一个组件,它的 history 对象是整个路由系统的核心,它暴露了很多属性和方法在路由系统中使用。Router 组件可以用来包裹一组 Route 组件。
(2)、Redirect 组件
Redirect 是一个重定向组件,有 from 和 to 两个属性。
(3)、Link 组件
Link 是一个组件,替代 a标签。它的属性有:
- to 为链接的名称。
- activeClassName 为链接被激活的类名。
- activeStyle 链接被激活时的样式。
3、特性
(1)、支持 mixin
var Assignment = React.createClass({mixins: [ History ],navigateAfterSomethingHappened () {// 路由器现在基于rackt/history构建,是一流的// 路由器中用于导航的APIthis.history.pushState(null, `/users/${user.id}`, query);// this.history.replaceState(null, `/users/${user.id}`, query);}
})
4、API
API 参考
(1)、生命周期
提供了一些生命周期钩子函数:
onEnter(nextState, replaceState, callback?)
- 在即将进入路线时调用。它提供下一个路由器状态和重定向到另一条路径的功能。this将是触发钩子的路由实例。
- 如果callback被列为第三个参数,这个钩子将异步运行,并且转换将阻塞直到callback被调用。
onUpdate()
:每当路由器更新其状态以响应 URL 更改时调用。onLeave()
:当路由即将退出时调用。
5、一般的使用案例
更多官方案例
// active-links/app.js
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, Link, IndexLink } from 'react-router'
import { createHistory, useBasename } from 'history'class App extends React.Component {render() {return (<div><h1>APP!</h1><ul><li><Link to="/">/</Link></li><li><IndexLink to="/">/ IndexLink</IndexLink></li><li><Link to="/users">/users</Link></li><li><IndexLink to="/users">/users IndexLink</IndexLink></li><li><Link to="/users/ryan">/users/ryan</Link></li><li><Link to="/users/ryan" query={{ foo: 'bar' }}>/users/ryan?foo=bar</Link></li><li><Link to="/about">/about</Link></li></ul>{this.props.children}</div>)}
}class Index extends React.Component {render() {return (<div><h2>Index!</h2></div>)}}
class Index extends React.Component {render() {return (<div><h2>Users</h2></div>)}}
class Index extends React.Component {render() {return (<div><h3>UsersIndex</h3></div>)}}
class Index extends React.Component {render() {return (<div><h3>User {this.props.params.id}</h3></div>)}}
class Index extends React.Component {render() {return (<div><h2>About</h2></div>)}}const history = useBasename(createHistory)({basename: '/active-links'
})render((<Router history={history}><Route path="/" component={App}><IndexRoute component={Index}/><Route path="/about" component={About}/><Route path="users" component={Users}><IndexRoute component={UsersIndex}/><Route path=":id" component={User}/></Route></Route></Router>
), document.getElementById('example'))
【参考文章】
react-router v1.0.0 入门
深入理解 react-router 路由系统
二、React-Router v2
v2.0.0 官方,具体变更内容请查看其“线路图”。
一些概念请看这里:词汇表,变化不大。
内置组件也没有变化。
API 参考这里: API 参考,生命周期没有变化。
1、特性
(1)、用 browserHistory 代替 createBrowserHistory
弃用 createBrowserHistory 进行跳转,改用 browserHistory:
// v1.0.0
import createBrowserHistory from 'history/lib/createBrowserHistory'
render(<Router history={createBrowserHistory()}/>, el)// v2.0.0
import { browserHistory } from 'react-router'
render(<Router history={browserHistory}/>, el)
(2)、用 render 属性代替 RoutingContext 属性
在 Router 组件上弃用 RoutingContext 属性,改用 render 属性:
// v1.0.0
render(<Router RoutingContext={AsyncProps}/>, el)// v2.0.0
render((<Router render={(props) => (<AsyncProps {...props} render={(props) => (<RoutingContext {...props} />)}/>)}/>
), el)
(3)、弃用 mixin
// v1.0.0
const RouteComponent = React.createClass({mixins: [ Lifecycle ],routerWillLeave() {// ...}
})// v2.0.0
const RouteComponent = React.createClass({componentDidMount() {const { router, route } = this.propsrouter.addRouteLeaveHook(route, this.routerWillLeave)}
})
2、一般的使用案例
更多官方案例
// active-links/app.js
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, Link, IndexLink, browserHistory } from 'react-router'class App extends React.Component {render() {return (<div><h1>APP!</h1><ul><li><Link to="/">/</Link></li><li><IndexLink to="/">/ IndexLink</IndexLink></li><li><Link to="/users">/users</Link></li><li><IndexLink to="/users">/users IndexLink</IndexLink></li><li><Link to="/users/ryan">/users/ryan</Link></li><li><Link to={{ pathname: '/users/ryan', query: { foo: 'bar' } }}>/users/ryan?foo=bar</Link></li><li><Link to="/about">/about</Link></li></ul>{this.props.children}</div>)}
}class Index extends React.Component {render() {return (<div><h2>Index!</h2></div>)}}
class Index extends React.Component {render() {return (<div><h2>Users</h2>{this.props.children}</div>)}}
class Index extends React.Component {render() {return (<div><h3>UsersIndex</h3></div>)}}
class Index extends React.Component {render() {return (<div><h3>User {this.props.params.id}</h3></div>)}}
class Index extends React.Component {render() {return (<div><h2>About</h2></div>)}}render((<Router history={browserHistory}><Route path="/" component={App}><IndexRoute component={Index}/><Route path="/about" component={About}/><Route path="users" component={Users}><IndexRoute component={UsersIndex}/><Route path=":id" component={User}/></Route></Route></Router>
), document.getElementById('example'))
三、React-Router v3
React-Router v3 官网
v3.0.0,具体变更内容请查看其“线路图”。
一些概念请看这里:词汇表,变化不大。
内置组件也没有变化。
API 参考这里: API 参考,生命周期没有变化。
React-Router v3 相比于 v2 并没有引入任何新的特性,只是将 v2 版本中部分废弃 API 的 warning 移除掉而已。如果你已经在使用 v2 的版本,那么升级 v3 将不会有任何额外的代码变动。
1、一般的使用案例
更多官方案例
// active-links/app.js
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, Link, IndexLink, browserHistory } from 'react-router'
import withExampleBasename from '../withExampleBasename'const App = ({ children }) => (<div><h1>APP!</h1><ul><li><Link to="/">/</Link></li><li><IndexLink to="/">/ IndexLink</IndexLink></li><li><Link to="/users">/users</Link></li><li><IndexLink to="/users">/users IndexLink</IndexLink></li><li><Link to="/users/ryan">/users/ryan</Link></li><li><Link to={{ pathname: '/users/ryan', query: { foo: 'bar' } }}>/users/ryan?foo=bar</Link></li><li><Link to="/about">/about</Link></li></ul>{children}</div>
)const Index = () => (<div><h2>Index!</h2></div>)
const Users = ({ children }) => (<div><h2>Users</h2>{children}</div>)
const UsersIndex = () => (<div><h3>UsersIndex</h3></div>)
const User = ({ params: { id } }) => (<div><h3>User {id}</h3></div>)
const About = () => (<div><h2>About</h2></div>)render((<Router history={withExampleBasename(browserHistory, __dirname)}><Route path="/" component={App}><IndexRoute component={Index}/><Route path="/about" component={About}/><Route path="users" component={Users}><IndexRoute component={UsersIndex}/><Route path=":id" component={User}/></Route></Route></Router>
), document.getElementById('example'))
// withExampleBasename.js
import useBasename from 'history/lib/useBasename'// 该助手用于在具有最小样板的示例上设置basename。在实际应用程序中,您将构建一个自定义历史记录来设置basename。
export default function withExampleBasename(history, dirname) {return useBasename(() => history)({ basename: `/${dirname}` })
}
四、React-Router v4
React-Router v4/v5 官网
React Router v4 是完全重写的,所以并没有简单的建议迁移方式。
React Router V4 遵循了 React 的理念:万物皆组件。因此 升级之后的 Route、Link、Switch 等都是一个普通的真正的组件。
1、拆包
React Router V4 基于 Lerna 管理多个代码库,将 react-router 拆分成了多个包:
react-router
:路由核心库。不包含对 DOM 的操作。react-router-dom
:适用于浏览器环境的再次封装。- 包含了 react-router 的核心部分。
- 比 react-router 多出了 <Link> <BrowserRouter> 这样的 DOM 类组件。
react-router-native
:适用于 react-native 环境。- 包含了 react-router 的核心部分。
react-router-config
:静态路由配置助手。
【拓展】react-router v4 其实还分出了一个包叫 react-router-redux
,但是官方自 v4.3.0 版本开始就它不再维护了,官方给出的解释是:集成 Redux 和 DOM History API 具有挑战性,因为它们不保持相同的语义,并且由此产生的集成很容易出错。所以不推荐使用 react-router-redux 包。对于 react-router-redux 有大佬踩坑记录可供参阅避坑:React Router v4 几乎误我一生。
2、组件
(1)、<Route> 组件
<Route> 组件有如下属性:
- path(string): 路由匹配路径。(没有 path 属性的 Route 总是会 匹配)。
- exact(bool):为 true 时,则要求路径与 location.pathname 必须完全匹配。
- strict(bool):为 true 时,有结尾斜线的路径只能匹配有斜线的 location.pathname。
exact 配置案例:
路径 | location.pathname | exact | 是否匹配 |
---|---|---|---|
/one | /one/two | true | 否 |
/one | /one/two | false | 是 |
strict 配置案例:
路径 | location.pathname | strict | 是否匹配 |
---|---|---|---|
/one/ | /one | true | 否 |
/one/ | /one/ | true | 是 |
/one/ | /one/two | true | 是 |
<Route> 组件提供了 3 种渲染内容的方法:
<Route component>
:在地址匹配的时候 React 的组件才会被渲染,route props 也会随着一起被渲染。这种渲染方式与 v4 之前版本里的 Route 一样。<Route render>
:这种方式对于内联渲染和包装组件却不引起意料之外的重新挂载特别方便。<Route children>
:与 render 属性的工作方式基本一样,除了它是不管地址匹配与否都会被调用。
重点看下 <Route render> 的渲染方式:
// 行内渲染示例
<Route path="/home" render={() => <div>Home</div>}/>// 包装/合成
const FadingRoute = ({ component: Component, ...rest }) => (<Route {...rest} render={props => (<FadeIn><Component {...props}/></FadeIn>)}/>
)<FadingRoute path="/cool" component={Something}/>
【注意】<Route component> 的优先级要比 <Route render> 高,所以不要在同一个 <Route> 中同时使用这两个属性。
(2)、<Router> 组件
在 4.0 之前版本中:
- <Router> 组件的 children 只能是 React Router 提供的各种组件,如 <Route>、<IndexRoute>、<Redirect> 等。
- <Router> 组件下允许同时存在多个子元素。
在 React Router v4 中:
- 可以将各种组件及标签放进 <Router> 组件中——以实现 <Router> 和
location
保持同步。 - <Router> 组件下只允许存在一个子元素。
例如:
// V2 or V3
import { Router, Route, hashHistory } from 'react-router';<Router history={hashHistory}><Route path='/foo' component={Foo} /><Route path='/bar' component={Bar} />
</Router>// V4 Router组件里只能渲染一个组件
import { HashRouter as Router, Route } from 'react-router-dom';<Router><div><Route path='/foo' component={Foo} /><Route path='/bar' component={Bar} /></div>
</Router>
<Route> 组件是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由器组件:
- <BrowserRouter>:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步。
- <HashRouter>:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步。
- <MemoryRouter>:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写)。
- <NativeRouter>:为使用 React Native 提供路由支持。
- <StaticRouter>:从不会改变地址。
(3)、<Link> 组件
和之前版本没太大区别,重点看下组件属性:
- to(string/object):必须的(在之前的版本中可省略)。表示要跳转的路径地址。
- replace(bool):
- 默认为 false。为 false 时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。
- 为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址。
例如:
import { Link } from 'react-router-dom';// to 为 string
<Link to="/about">关于</Link>// to为obj
<Link to={{pathname: '/courses',search: '?sort=name',hash: '#the-hash',state: { fromDashboard: true }
}}/>// replace
<Link to="/courses" replace />
(4)、<NavLink> 组件
<NavLink> 组件是一个特殊的 <Link> 组件,会在匹配上当前 URL 的时候,给已经渲染的元素添加样式参数。一般会用其实现导航栏。
<NavLink> 组件属性:
- activeClassName(string):设置选中样式,默认值为 active。
- activeStyle(object):当元素被选中时, 为此元素添加样式。
- exact(bool):为 true 时, 只有当地址完全匹配 class 和 style 才会应用。
- strict(bool):为 true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线。
- isActive(func):判断链接是否激活的额外逻辑的功能。
使用案例:
import { NavLink} from 'react-router-dom';// activeClassName 选中时样式为selected
<NavLink to="/faq" activeClassName="selected">FAQs</NavLink>// 选中时样式为 activeStyle 的样式设置
<NavLink to="/faq" activeStyle={{ fontWeight: 'bold', color: 'red' }}>FAQs</NavLink>// 当 event id 为奇数的时候,激活链接
<NavLink to="/events/123" isActive={oddEvent}>Event 123</NavLink>
const oddEvent = (match, location) => {if (!match) {return false}const eventID = parseInt(match.params.eventID)return !isNaN(eventID) && eventID % 2 === 1
}
(5)、<Switch> 组件
<Switch> 组件用来渲染第一个匹配的 <Route> 或 <Redirect> 组件。
<Switch> 组件与使用一堆 <Route> 组件有什么区别呢?
假设有下面是三个路由:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
如果现在的 URL 是 /about
,那么 <About>、 <User> 以及 <NoMatch> 都会被渲染,因为它们都与路径(path)匹配。这种设计,允许我们以多种方式将多个 <Route> 组合到我们的应用程序中,例如:侧栏(sidebars)、面包屑(breadcrumbs)、bootstrap tabs 等等。
然而,偶尔我们只想选择一个 <Route> 来渲染。如果我们现在处于 /about
,我们也不希望匹配 /:user
(或者显示我们的 “404” 页面 )。以下是使用 <Switch> 的方法来实现:
<Switch><Route exact path="/" component={Home}/><Route path="/about" component={About}/><Route path="/:user" component={User}/><Route component={NoMatch}/>
</Switch>
现在,如果我们处于 /about
,<Switch> 将开始寻找匹配的 <Route>。<Route path=“/about”/> 将被匹配, <Switch> 将停止寻找匹配并渲染 <About>。同样,如果我们处于 /michael
,<User> 将被渲染。
(6)、组件的嵌套
// V2 or V3 路由组件嵌套
import { Router, Route, hashHistory } from 'react-router';<Router history={hashHistory}><Route path='/' component={App}><Route path='foo' component={Foo} /><Route path='bar' component={Bar} /></Route>
</Router>// V4 Router 的路由组件嵌套
import { HashRouter as Router, Route, Switch } from 'react-router-dom';<Router><Route path="/" component={(props) => (<App {...props}><Switch><Route path='/foo' component={Foo} /><Route path='/bar' component={Bar} /></Switch></App>)}/>
</Router>
3、API
(1)、生命周期
React-Router v4 废除了自身的 3 个生命周期钩子函数,可用 React 的生命周期接管:
- 用 componentDidMount 或 componentWillMount 代替 onEnter。
- 用 componentWillUpdate 或 componentWillReceiveProps代替 onUpdate。
- 用 componentWillUnmount 代替 onLeave。
React-Router v4 对路由进行了改进,router 属性改为了 history 属性,使用方法还是和 3.0 差不多,任何需要跳转的地方使用this.props.history.push(‘/path’) 就可以进行跳转了。
(2)、history 对象
获取 react-router 里面的 history 库:
// V2 or V3
import {hashHistory as history} from 'react-router';// V4
import createHashHistory as history from 'history/createHashHistory';
history.push 和 history.replace
// V2 or V3
history.push({pathname: '/home',query: {foo: 'test',bar: 'temp'}
});
history.replace({pathname: '/home',query: {foo: 'test',bar: 'temp'}
});// V4
history.push({pathname: '/home',search: '?foo=test&bar=temp',
});
history.replace({pathname: '/home',search: '?foo=test&bar=temp',
});
BrowerHistory、HashHistory 和 createMemoryHistory 路由器的区别:
browserHistory
使用的是 HTML5 History API。- browserHistory 需要在服务器端进行额外配置来提供 URL。
- 它通常是现代网页的首选解决方案。
hashHistory
使用 URL 哈希以及查询键来跟踪状态。- URL 中有
#
。 - 刷新页面后为导致 URL 的参数丢失。
- URL 中有
createMemoryHistory
:实现服务器渲染的方式。
关于 react router 的 History,可以参考官方给出的这篇文档,如果要了解他的历史变更可以看这篇文档。
(3)、props 对象
props.params:获取到当前路由的参数。
// V2 or V3 获取params可以这么获取
this.props.params// V4
this.props.match.params
(4)、 location 对象
①、location.query
// V2 or V3 获取query可以这么获取
this.props.location.query// V4 去掉了location.query,只能使用search来获取,为了让其跟浏览器一样
// 如果想要兼容以前的location.query,可以使用query-string库解析一下
// 如: queryString.parse(props.location.search)
this.props.location.search
②、location.action
// V2 or V3 获取location的action
this.props.location.action// V4 去掉了location.action, 放在了history里面
history.action
4、一般的使用案例
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'// 三个基础呈现组件
const Home = () => (<div><h2>Home</h2></div>)
const About = () => (<div><h2>About</h2></div>)
const Topic = ({ match }) => (<div><h3>{match.params.topicId}</h3></div>)// 一个内嵌的组件
const Topics = ({ match }) => (<div><h2>Topics</h2><ul><li><Link to={`${match.url}/rendering`}>Rendering with React</Link></li><li><Link to={`${match.url}/components`}>Components</Link></li><li><Link to={`${match.url}/props-v-state`}>Props v. State</Link></li></ul><Route path={`${match.url}/:topicId`} component={Topic}/><Route exact path={match.url} render={() => (<h3>Please select a topic.</h3>)}/></div>
)// 首页组件
const BasicExample = () => (<Router><div><ul><li><Link to="/">Home</Link></li><li><Link to="/about">About</Link></li><li><Link to="/topics">Topics</Link></li></ul><Route exact path="/" component={Home}/><Route path="/about" component={About}/><Route path="/topics" component={Topics}/></div></Router>
)
export default BasicExample
【参考文章】
react-router 从v2/v3迁移到v4(译文)
ReactRouter升级 v2 to v4
React Router v4 入坑指南
React-Router v4 学习
由浅入深地教你开发自己的 React Router v4
心中无路由,处处皆自由/react-router v4 动态路由
五、React-Router v5
React-Router v4/v5 官网
v5.0.0
React-Router 官方团队原本只是计划发布 React Router 4.4 版本,但由于错误地将依赖写成 “react-router”: “^4.3.1”,导致报错。最后团队决定撤销这个错误的版本,直接改为发布 React Router v5。
React-Router v5 变化概述:
- 完全兼容老版本 v4。
- 支持 React 16 , 兼容 React >= 15。
- 消除在 React.StrictMode 严格模式中的警告。
- 使用 create-react-context 实现 context API。
1、组件
(1)、<Route> 组件的变化
- <Route> 组件支持路径数组了。
<Route path={["/BigApple", "/NYC", "NewYork"]} component={NewYork} />
- <Route> 组件支持多个子节点了(react >= 16.0)。
(2)、内置的路由器组件的引入方式变了
以 BrowserRouter 组件为例:
// v4
import BrowserRouter from 'react-router-dom/BrowserRouter';
import { Route } from 'react-router-dom';// v5
import { BrowserRouter, Route } from 'react-router-dom';
2、API
React-Router v4/v5 官网 中包含这个版本的 API。
(1)、新增一些 hooks API
React-Router v5 基于 React Hooks 新增了一些 hooks API(您需要使用 React >= 16.8 才能使用这些钩子):
useHistory
:访问可用于导航的历史记录实例。useLocation
:返回代表当前URL的 location 对象。你可以把它当成一个 useState hook,只要URL更改,它就会返回一个新位置。如果你希望每次加载新页面的时候都使用 web 分析工具除法新的“页面浏览”事件,这个 hook 将会非常有用。useParams
:返回URL参数的键/值对的对象。使用它来访问当前 <Route> 的match.params。useRouteMatch
:以与 <Route> 相同的方式匹配当前URL。它主要用于在无需实际呈现 <Route> 即可访问匹配数据的需求。
使用案例:
// useHistory
import { useHistory } from "react-router-dom";function HomeButton() {let history = useHistory();function handleClick() {history.push("/home");}return (<button type="button" onClick={handleClick}>Go home</button>);
}
// useLocation
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Switch, useLocation } from "react-router-dom";function usePageViews() {let location = useLocation();React.useEffect(() => {ga.send(["pageview", location.pathname]);}, [location]);
}function App() {usePageViews();return <Switch>...</Switch>;
}ReactDOM.render(<Router><App /></Router>,node
);
// useParams
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom";function BlogPost() {let { slug } = useParams();return <div>Now showing post {slug}</div>;
}ReactDOM.render(<Router><Switch><Route exact path="/"><HomePage /></Route><Route path="/blog/:slug"><BlogPost /></Route></Switch></Router>,node
);
// useRouteMatch
import { useRouteMatch } from "react-router-dom";function BlogPost() {let match = useRouteMatch("/blog/:slug");return <div />;
}
(2)、弃用 2 个 react 的生命周期方法
自 v5 之后,React-Router 不再使用 react 的 componentWillMount 和 componentWillReceiveProps 这两个生命周期了。
在 React-Router v5 中可用的 React 的生命周期:
componentDidMount
。componentWillUpdate
。componentWillUnmount
。
(3)、withRouter 函数
您可以通过 withRouter 高阶组件访问 history 对象的属性和最接近的 <Route> 匹配。无论何时呈现,withRouter 都会将更新的 match、location 和 history 属性传递给包装组件。
import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";// 显示当前位置路径名的简单组件
class ShowTheLocation extends React.Component {static propTypes = {match: PropTypes.object.isRequired,location: PropTypes.object.isRequired,history: PropTypes.object.isRequired};render() {const { match, location, history } = this.props;return <div>You are now at {location.pathname}</div>;}
}// 创建一个“连接”的新组件(借用redux术语)发送到路由器。
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
【注意】除非其父组件重新渲染,否则不会在路由转换时重新渲染 withRouter。
withRouter 提供了 WrappedComponentRef 属性,该属性用来:将作为 ref 道具传递给包装组件的函数。
class Container extends React.Component {componentDidMount() {this.component.doSomething();}render() {return (<MyComponent wrappedComponentRef={c => this.component = c} />)}
}
3、一般的使用案例
React-Router v4/v5 官网 中包含一系列的“使用案例”。
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";/* 该网站有3个页面,所有页面都在浏览器中动态呈现(而不是服务器呈现)。
尽管页面不会刷新,但请注意,当您浏览站点时,React Router如何使URL保持最新。
这将保留浏览器历史记录,确保后退按钮和书签等功能正常工作。
*/
const Example = function BasicExample() {return (<Router><div><ul><li><Link to="/">Home</Link></li><li><Link to="/about">About</Link></li><li><Link to="/dashboard">Dashboard</Link></li></ul>/* <Switch>查找其所有子<Route>元素,并呈现路径与当前URL匹配的第一个元素。当您有多条路线,但希望一次只渲染其中一条路线时,可以使用<Switch> */<Switch><Route exact path="/"><Home /></Route><Route path="/about"><About /></Route><Route path="/dashboard"><Dashboard /></Route></Switch></div></Router>);
}// 您可以将这些组件视为应用程序中的“页面”。
function Home() {return (<div><h2>Home</h2></div>)}
function About() {return (<div><h2>About</h2></div>)}
function Dashboard() {return (<div><h2>Dashboard</h2></div>)}ReactDOM.render(<Example />,document.getElementById('root')
);
【参考文章】
React Router 中文文档(v5 )
最新 React Router 全面整理
六、React-Router v6
React-Router v6 官网
v6.0.0
若打算升级路由到 v6,官方建议先从 v5 升级到 v5.1(请参阅此文)。
- 要在 v5.1 中使用 <Route children>——这将有助于平滑过渡到 v6。不要在 v5.1 中使用 <Route component> 和 <Route render> ,凡是使用他们的都统统替换成使用常规元素 <Route children>。
- 要在 v5.1 中使用 hooks 来访问路由器的内部状态。
1、组件
(1)、<Routes> 替换 <Swicth>
在 v6 中,<Routes> 替换了 <Swicth> 组件。
在使用 <Route> 组件时,必须用 <Routes> 组件包裹,也就是 “Routes --> Route” 的组合。
// v5
<Swicth><Route path="/about" element={<About />} /><Route path="/home" element={<Home />} />
</Swicth>// v6
<Routes><Route path="/about" element={<About />} /><Route path="/home" element={<Home />} />
</Routes>
<Route> 组件相当于 if 语句,如路径和当前的 url 匹配,则呈现对应的组件。
<Route> 组件也可以嵌套使用,且配合 useRoutes 钩子配置路由表,但需要通过 <Outlet> 组件来渲染子路由。
(2)、<Outlet> 组件
<Outlet> 组件专门用来实现“嵌套路由”——父路由元素中应使用<Outlet>来呈现其子路由元素。如果父路由完全匹配,则将呈现子索引路由,如果没有索引路由,则不呈现任何内容。
【拓展】react-router 里的 <Outlet /> 组件相当于 vue-router 里的 <router-view /> 组件。
function Dashboard() {return (<div><h1>Dashboard</h1>/* 当URL为“/messages”时,此元素将呈现<DashboardMessages>,当URL为“/tasks”时,此元素将呈现<DashboardTasks>,当URL为“/”则呈现null*/<Outlet /></div>);
}function App() {return (<Routes><Route path="/" element={<Dashboard />}><Routepath="messages"element={<DashboardMessages />}/><Route path="tasks" element={<DashboardTasks />} /></Route></Routes>);
}
(3)、<Navigate> 替换 <Redirect>
在 v6 中,<Navigate> 替换了 <Redirect> 组件。
// v5
<Route path="*" element={<Redirect to="/about" />} />// v6
<Route path="*" element={<Navigate to="/about" />} />
2、特性
(1)、<Route> 组件的特性变更
①、使用 element 属性替换原来的 component 属性
在 v6 版本中,<Route> 组件上使用 element 属性替换原来的 component 属性。element 属性里可以直接放组件。
<Route path="home" element={<Home />} />
②、新增 caseSensitive 属性
在 v6 版本中,<Route> 组件新增了 caseSensitive 属性,用来确定:是否以区分大小写的方式进行匹配。默认值为 false,表示“按照不区分大小写的方式进行路由匹配”。
③、弃用 exact 属性
在 v6 版本中,exact 属性已被移除,所有的路由都是“严格匹配”。
(2)、<NavLink/> 特性变更
在 v6 中,移除了<NavLink/> 的 activeClassName 和 activeStyle 属性。改变 NavLink 选中样式可以像修改其他 DOM 元素那样改变对应的 style 属性或 className 。
3、API
(1)、hooks
与 v6 之前的版本相比的变化:
- useNavigate 取代了 useHistory。
- useRouteMatch 被废弃了。
import { useNavigate } from 'react-router-dom';function Foo(){const navigate = useNavigate();return (// 上一个路径:/a; 当前路径: /a/a1<div onClick={() => navigate('/b')}>跳转到/b</div><div onClick={() => navigate('a11')}>跳转到/a/a1/a11</div><div onClick={() => navigate('../a2')}>跳转到/a/a2</div><div onClick={() => navigate(-1)}>跳转到/a</div>)
}
React-Router Hooks 列表:
hooks | 描述 |
---|---|
useActionData | 这个钩子提供上一个导航 action 结果的返回值,或者 undefined 如果没有提交。 |
useAsyncError | 从最近的 <Await> 组件返回拒绝值。 |
useAsyncValue | 从最近的 <Await> 祖先组件返回解析的数据。 |
useFetcher | 表单钩子。针对<Link>和<Form>,这个钩子可以让你将你的 UI 插入到你的操作和加载器中,而无需导航。 |
useFetchers | 表单钩子。返回所有 fetchers 的数组,但不包含其加载、提交或表单属性(不能让父组件尝试控制其子组件的行为,这是徒劳的。) |
useFormAction | 表单钩子。此钩子在内部 <Form> 用于自动将默认和相关操作解析为上下文中的当前路由。 |
useHref | 该钩子返回一个 URL,该 URL 可用于链接到给定 to 位置,甚至在 React Router 之外。 |
useInRouterContext(★) | 如果组件在 <Router> 的上下文中呈现,则useInRouterContext钩子返回true,否则返回false。这对于需要知道是否在React Router应用程序上下文中呈现的第三方扩展非常有用。 |
useLinkClickHandler | 在react router dom中构建自定义<Link>时,useLinkClickHandler钩子返回用于导航的点击事件处理程序。 |
useLinkPressHandler | react router与useLinkClickHandler的本机对应,useLinkPressHandler返回用于自定义<Link>导航的按下事件处理程序。 |
useLoaderData | 这个钩子提供从路由加载器返回的值。 |
useLocation | 这个钩子返回当前 location 对象。如果您希望在当前位置发生变化时执行一些副作用,这可能很有用。 |
useMatch | 返回给定路径上相对于当前位置的路线的匹配数据。有关更多信息,请参阅 matchPath。 |
useMatches | 返回页面上的当前路由匹配项。这对于在父布局中创建抽象以访问其子路由的数据非常有用。 |
useNavigate(★) | useNavigate钩子返回一个函数,该函数允许您以编程方式导航。官方提示:在加载器和操作中使用 redirect 通常比这个钩子更好。 |
useNavigation | 这个钩子告诉您关于页面导航所需了解的所有信息,以构建挂起的导航指示符和关于数据变化的乐观UI。 |
useNavigationType(★) | 此钩子返回当前导航类型或用户如何到达当前页面;通过历史堆栈上的弹出、推送或替换操作。(返回用户是如何来到当前页面的。返回值:pop(刷新当前页面)、push、replace) |
useOutlet(★) | 返回路由层次结构中此级别的子路由的元素。<Outlet>在内部使用此钩子来呈现子路由。(用来呈现当前组件中渲染的嵌套路由组件,如果嵌套路由组件已经挂在,则显示嵌套路由对象,否则为null) |
useOutletContext | 通常,父路由管理希望与子路由共享的状态或其他值。如果愿意,您可以创建自己的 context provider,但这是一种常见情况,它内置于<Outlet/>中。 |
useParams | useParams钩子从当前URL返回一个动态参数的键/值对的对象,这些动态参数与<oute path>匹配。子路由从其父路由继承所有参数。 |
useResolvedPath(★) | 此钩子根据当前位置的路径名解析给定 to 值中位置的路径名称。(解析一个url,解析其中的path,search,hash) |
useRevalidator | 此挂钩允许您出于任何原因重新验证数据。在调用操作后,React Router会自动重新验证数据,但您可能出于其他原因需要重新验证,例如当焦点返回窗口时。 |
useRouteError | 在 errorElement 内部,该钩子返回在操作、加载程序或呈现期间抛出的任何内容。请注意,抛出的响应有特殊处理,有关更多信息,请参阅 isRouteErrorResponse。 |
useRouteLoaderData | 此钩子使当前渲染的任何路线上的数据在树中的任何位置都可用。这对于树中较深的组件非常有用,这些组件需要来自更远的路由的数据,以及需要树中较深处的子路由的数据的父路由。 |
useRoutes(★) | useRoutes钩子在功能上等同于<Routes>,但它使用JavaScript对象而不是<Route>元素来定义路由。这些对象具有与普通<Route>元素相同的属性,但不需要JSX。 |
useSearchParams | useSearchParams钩子用于读取和修改当前位置URL中的查询字符串。像React自己的useState钩子一样,useSearchParams返回两个值的数组:当前位置的搜索参数和一个可用于更新它们的函数。正如React的useState钩子一样,searchParams也支持功能更新。因此,您可以提供一个函数,该函数接受searchParams并返回更新版本。 |
useSubmit | <Form>的命令式版本,让程序提交表单,而不是用户。 |
4、一般的使用案例
import { Routes, Route, Link, useParams, Outlet } from 'react-router-dom'
import './App.scss'function Nav() {return (<nav><Link to="/">Home</Link><Link to="/about">About</Link><Link to="/article/1">Article</Link><Link to="/contact">Contact</Link></nav>)
}
function Home() {return (<main><h2>Home</h2><Nav /></main>)
}
function About() {return (<main><h2>About</h2><Nav /></main>)
}
function Comment() { return <div>This is comment list.</div> }
function Statistics() { return <div>This is statistics.</div> }
function Article() {let params = useParams()return (<main><h2>Article</h2><Nav /><p>id: {params.id}</p><Link to="comment">Comment</Link><Link to="statistics">Statistics</Link><Routes><Route path="comment" element={<Comment />} /><Route path="statistics" element={<Statistics />} /></Routes></main>)
}
function Contact() {return (<main><h2>Contact</h2><Nav /><Link to="address">Address</Link><Link to="phone">Phone</Link><Outlet></Outlet></main>)
}function ContactIndex() { return <div>ContactIndex</div> }
function Address() { return <div>This is address: xxxxxxxxxxx</div> }
function Phone() { return <div>This is phone: xxxxxxxxxxx</div> }
function NotFound() { return <div>404 Not Found</div> }function App() {return (<div className="App"><h1>Welcome to React Router!</h1><Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} /><Route path="/contact" element={<Contact />}><Route index element={<ContactIndex />}></Route><Route path="address" element={<Address />}></Route><Route path="*" element={<NotFound />} /><Route path="phone" element={<Phone />}></Route></Route><Route path="/article/:id/*" element={<Article />} /><Route path="*" element={<NotFound />} /></Routes></div>)
}export default App
【参考文章】
react-router-dom v6版本与v5版本对比及v5版本相关替代方案
react-router-dom使用指南(最新V6.0.1)
react-router v6 如何实现动态路由?
React 之Router路由(含5.0与6.0版本)(推荐)
React Router v6 使用指南
React学习之——Router(v6)(推荐)
「React进阶」react-router v6 通关指南
React Router (V6)
【推荐文章】
官方文档:Introduction | React Router 中文文档
聊一聊 React-Router
React Router 使用教程——阮一峰
React Router教程——IT老马
React系列十九 - 掌握react-router
前端路由实现与 react-router 源码分析
深入理解 react-router 路由系统
react router相关推荐
- React router 的 Route 中 component 和 render 属性理解
React router 的 Route 中 component 和 render 属性理解 Route 标签的三个互斥属性 render.component.children Route 就是用来匹 ...
- router路由react_使用React Router在React中受保护的路由
router路由react In this video, you will see how to create a protected route using React Router. This r ...
- hitchhiker部署_Hitchhiker的React Router v4指南:无限远的递归路径!
hitchhiker部署 Welcome to the third part of the Hitchhiker's Guide to React Router v4. In this article ...
- [React Router v4] Intercept Route Changes
If a user has entered some input, or the current Route is in a "dirty" state and we want t ...
- 使用React Router以编程方式导航
通过react-router我可以使用Link元素来创建由react路由器本地处理的链接. 我在内部看到它调用this.context.transitionTo(...) . 我想从下拉列表中进行导航 ...
- 从 React Router 谈谈路由的那些事
React Router 是专为 React 设计的路由解决方案,在使用 React 来开发 SPA (单页应用)项目时,都会需要路由功能,而 React Router 应该是目前使用率最高的. Re ...
- [React Router v4] Conditionally Render a Route with the Switch Component
We often want to render a Route conditionally within our application. In React Router v4, the Route ...
- 初探 React Router 4.0
React Router 4.0 (以下简称 RR4) 已经正式发布,它遵循React的设计理念,即万物皆组件.所以 RR4 只是一堆 提供了导航功能的组件(还有若干对象和方法),具有声明式(引入即用 ...
- React Router 使用教程
真正学会 React 是一个漫长的过程. 你会发现,它不是一个库,也不是一个框架,而是一个庞大的体系.想要发挥它的威力,整个技术栈都要配合它改造.你要学习一整套解决方案,从后端到前端,都是全新的做法. ...
- hitchhiker部署_《 Hitchhiker的React Router v4指南》:路由配置的隐藏值
hitchhiker部署 Welcome to the Hitchhiker's Guide to React Router v4, Part IV! 欢迎来到< React Router v4 ...
最新文章
- 用Ghost几秒钟快速格式化120G大硬盘
- python基础之day1
- 【动态规划】最长公共上升子序列
- 微博收藏(机器学习探讨)(二)
- Linux 关闭、开启、查看 防火墙命令
- web前端开发技术期末考试_智慧树来我校开展WEB前端开发微专业导学
- 图形用户界面和交互输入方法---图形用户界面的设计
- 转载------工作10年的人总结的6句话
- 盒子模型(悬挂式布局)
- HDU-1253-胜利大逃亡(bfs)
- OCA读书笔记(11) - 实现Oracle数据库审计
- UVA 1584 环状序列
- 蓝牙Android_Lightblue调试工具存在的bug
- 关于主机的思维导图_「停课不停学」思维导图—初中数学全部知识点总结,高清可打印...
- windows动态库和静态库
- Android实用视图动画及工具系列之九:漂亮的图片选择器,高性能防崩溃图片选择工具
- HR-Saas(二):登录模块
- linux Mint桌面美化
- 云服务器运维兼职,云服务器的维护工作主要有哪些?
- 使用Assimp库读取mtl文件数据
热门文章
- 经典图像复原算法的matlab实现汇总
- 普及json格式相关问题
- 部分安卓游戏可在华为鸿蒙OS上运行
- zookeeper的C客户端API介绍及编译测试程序(未完待续11/01,缺测试程序)
- systemtap mysql_SystemTap
- 微信小程序推送消息java开发_干货 | 微信小程序推送消息简单Demo
- Android+8.0+微信表情,微信表情包不会动是怎么回事 安卓微信8.0更新表情特效怎么弄?...
- Mysql高级(锁、日志)
- python中单斜杠_Python中的正斜杠与反斜杠
- addAll方法——向Set集合添加另一个集合的所有内容