Create by jsliang on 2019-04-26 13:13:18
Recently revised in 2019-04-29 15:25:01php
Hello 小伙伴们,若是以为本文还不错,记得给个 star , 小伙伴们的 star 是我持续更新的动力!GitHub 地址html
【2019-08-16】Hello 小伙伴们,因为 jsliang 对文档库进行了重构,这篇文章中的一些连接可能失效,而 jsliang 缺少精力维护掘金这边的旧文章,对此深感抱歉。请须要获取最新文章的小伙伴,点击上面的 GitHub 地址,去文档库查看调整后的文章。前端
不折腾的前端,和咸鱼有什么区别react
返回目录git
前端路由,是指改变 URL 路径的形式,从而切换到不一样的页面,例如:github
localhost:3000/home
localhost:3000/user
经过切换不一样的 URL,显示不一样的页面,从而有了 路由 的概念。web
这篇文章咱们讲解在 React 中如何经过 React Router 这个插件,灵活使用路由。ajax
jsliang 瞎吹的,最好本身百度 前端路由 是啥。npm
网上有不少 React Router 文章了,例如:redux
为什么 jsliang 要屡次一举?
当前版本:"react-router-dom": "^5.0.0"
首先,在 Create React App 中,咱们引用 React Router:
npm i react-router-dom -S
而后,在 src 目录下新建 pages 用来存放页面,并修改 App.js:
案例:App.js
import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';
function App() {
return (
<Fragment> <BrowserRouter> <Header /> <ScrollToTop> <Switch> <Redirect from="/" to="/timeline" exact /> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </ScrollToTop> </BrowserRouter> </Fragment> ); } export default App; 复制代码
最后,经过在 App.js 中如此定义,便可定义对应的组件,并渲染对应页面和进行跳转。
下面咱们拿一些经常使用的进行介绍:
import {
BrowserRouter,
HashRouter,
Redirect,
Route,
NavLink,
Link,
MemoryRouter,
Switch,
withRouter
} from "react-router-dom";
复制代码
<BrowserRouter>
:路由组件包裹层。<Route>
和 <Link>
的包裹层。<HashRouter>
:路由组件包裹层。相对于 <BrowserRouter>
来讲,更适合静态文件的服务器。<Redirect>
:路由重定向。渲染 <Redirect>
将使导航到一个新的地址。<Route>
:路由。定义一个路由页面,用来匹配对应的组件(Component)和路由路径。<NavLink>
:活跃连接。当 URL 中的路径等于该路由定义的路径时,该标签能够呈现它定义的 activeClassName
。<Link>
:连接。用来跳转到 <Route>
对应的路由(Component) 中。<MemoryRouter>
:暂未使用。<Router>
能在内存中保存 URL
的历史记录。很适合在测试环境和非浏览器环境中使用,例如 React Native。<Switch>
:路由分组。渲染与该地址匹配的第一个子节点 <Route>
或者 <Redirect>
。能够利用 <Switch>
作分组。<withRouter>
:路由组合。经过 <withRouter>
高阶组件访问 history
对象的属性和最近的 <Route>
的 match
。或者利用它来结合 Redux。<BrowserRouter>
会为你建立一个专门的 history 对象,用来记录你的路由,从而可以返回上一页或者跳转到指定的路由页面。
区别于
<HashRouter>
,有响应请求的服务器时使用<BrowserRouter>
,使用的是静态文件的服务器,则用<HashRouter>
。
简单案例:
<BrowserRouter>
<Header /> <Route path="/" exact component={TimeLine}></Route> <Route path="/timeline" component={TimeLine}></Route> </BrowserRouter>
复制代码
import { BrowserRouter } from 'react-router-dom'
<BrowserRouter
basename={optionalString}
forceRefresh={optionalBool}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App/>
</BrowserRouter>
复制代码
basename: string
为里面的子目录提供基础路径名,例如:
<BrowserRouter basename="/calendar">
<Link to="/today"/> {/* 渲染为 <a href="/calendar/today"> */} </BrowserRouter> 复制代码
getUserConfirmation: function
用于确认导航的功能。
// 默认使用 window.confirm。
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation}/>
复制代码
forceRefresh: bool
若是为 true,则路由器将在页面导航中使用整页刷新
const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>
复制代码
keyLength: number
设置它里面路由的 location.key
的长度。默认为 6。
key 的做用:点击同一个连接时,每次该路由下的 location.key都会改变,能够经过 key 的变化来刷新页面。
<BrowserRouter keyLength={12}/>
复制代码
使用 URL
的 hash
部分(即 window.location.hash
)的 <Router>
使 UI
与 URL
保持同步。
重要提示:Hash
历史记录不支持 location.key
或 location.state
。
import { HashRouter } from 'react-router-dom'
<HashRouter>
<App/>
</HashRouter>
复制代码
basename: string
全部位置的基本 URL
,格式正确的基本名应该有一个前导斜线,但结尾不能有斜线。
<HashRouter basename="/calendar"/>
<Link to="/today"/>
{/* 渲染为 <a href="/calendar/today"> */}
复制代码
getUserConfirmation: func
用于确认导航的功能。默认使用 window.confirm。
// this is the default behavior
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<HashRouter getUserConfirmation={getConfirmation}/>
复制代码
hashType: string
用于 window.location.hash
的编码类型。可用的值是:
slash
- 建立 #/
和的 #/sunshine/lollipops
noslash
- 建立 #
和的 #sunshine/lollipops
hashbang
- 建立 ajax crawlable
,如 #!/
和 #!/sunshine/lollipops
默认为 slash
。
在应用程序周围提供声明式的,可访问的导航。
to: string
连接位置的字符串表示,经过链接位置的路径名,搜索和 hash
属性建立。
<Link to='/courses?sort=name'>字符串形式跳转</Link>
复制代码
to: object
一个能够具备如下任何属性的对象:
pathname
: 表示要连接到的路径的字符串。search
: 表示查询参数的字符串形式。hash
: 放入网址的 hash
,例如 #a-hash
。state
: 状态持续到 location
。<Link to={{
pathname: '/courses', // 基础路径
search: '?sort=name', // 匹配字段
hash: '#the-hash', // 对应内链
state: { fromDashboard: true } // 未知
}}>
对象形式跳转
</Link>
复制代码
replace: bool
若是为 true
,则单击连接将替换历史堆栈中的当前入口,而不是添加新入口。
<Link to="/courses" replace>替换当前 hash 路径</Link>
复制代码
还能够传递想要放在 <a>
上的属性,例如标题,ID
、className
等。
<Link to="/test" id="myTest">测试 1</Link>
复制代码
一个特殊版本的 Link,当它与当前 URL 匹配时,为其渲染元素添加样式属性。
<NavLink to="/timeline" activeClassName="active">首页</NavLink>
activeClassName: string
要给出的元素的类处于活动状态时。默认的给定类是 active
。它将与 className
属性一块儿使用。
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
复制代码
activeStyle: object
当元素处于 active 时应用于元素的样式。
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
复制代码
exact: bool
若是为 true
,则仅在位置彻底匹配时才应用 active
的类/样式。
<NavLink
exact
to="/profile"
>Profile</NavLink>
复制代码
isActive: function
一个为了肯定连接是否处于活动状态而添加额外逻辑的函数,若是你想作的不只仅是验证连接的路径名与当前 URL 的 pathname 是否匹配,那么应该使用它
// 若是连接不只仅匹配 events/123,而是全部奇数连接都匹配
const oddEvent = (match, location) => {
if (!match) {
return false
}
const eventID = parseInt(match.params.eventID)
return !isNaN(eventID) && eventID % 2 === 1
}
<NavLink
to="/events/123"
isActive={oddEvent}
>Event 123</NavLink>
复制代码
<Router>
能在内存中保存 URL
的历史记录(并不会对地址栏进行读写)。很适合在测试环境和非浏览器环境中使用,例如 React Native。
<MemoryRouter>
<App/>
</MemoryRouter>
复制代码
initialEntries: array
history
栈中的一个 location
数组。这些多是具备 { pathname, search, hash, state }
或简单的 URL
字符串的完整地址对象。
<MemoryRouter
initialEntries={[ '/one', '/two', { pathname: '/three' } ]}
initialIndex={1}
>
<App/>
</MemoryRouter>
复制代码
initialIndex: number
在 initialEntries
数组中的初始化地址索引。
getUserConfirmation: function
用于确认导航的函数。在使用 <MemoryRouter>
时,直接使用 <Prompt>
,你必须使用这个选项。
keyLength: number
location.key
的长度。默认为 6。
渲染 <Redirect>
将使导航到一个新的地址。这个新的地址会覆盖 history
栈中的当前地址,相似服务器端(HTTP 3xx)的重定向。
咱们能够设置某个路由重定向到另外一个路由,例以下面即对 /
彻底匹配重定向到 /timeline
页面。
<Redirect from="/" to="/timeline" exact />
复制代码
from: string
重定向 from
的路径名。能够是任何 path-to-regexp
可以识别的有效的 URL
路径。
全部匹配的 URL
参数都提供给 to
中的模式。
必须包含在 to
中使用的全部参数。
to
未使用的其余参数将被忽略。
<Switch>
<Redirect from="/old-path" to="/new-path" /> <Route path="/new-path" component={Place} /> </Switch> 复制代码
to: string
重定向到的 URL
,能够是任何 path-to-regexp
可以理解有效 URL
路径。
在 to
中使用的 URL
参数必须由 from
覆盖。
<Redirect to="/somewhere/else" />
复制代码
to: object
重定向到的 location
,pathname
能够是任何 path-to-regexp
可以理解的有效的 URL
路径。
<Redirect
to={{
pathname: "/login",
search: "?utm=your+face",
state: { referrer: currentLocation }
}}
/>
复制代码
push: bool
当 true
时,重定向会将新地址推入 history
中,而不是替换当前地址。
<Redirect push to="/somewhere/else" />
复制代码
exact: bool
彻底匹配 from
。
只要应用程序位置与 Route 的路径匹配,组件就会被渲染。
只有当位置匹配时才会渲染的 React 组件。
<Route path="/user/:username" component={User}/>
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
复制代码
render: function
这容许方便的内联渲染和包裹,而不是上面那种不想要的从新安装的解释
能够传递一个在位置匹配时调用的函数,而不是使用属性为您建立新的 React element component
,该 render
属性接收全部相同的 route props
的 component
渲染属性。
// 行内编写
<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}/>
复制代码
children: function
有时你须要渲染路径是否匹配位置。在这些状况下,您可使用函数 children
属性,它的工做原理与渲染彻底同样,不一样之处在于它是否存在匹配。
children
渲染道具接收全部相同的 route props
做为 component
和 render
方法,若是 Route
与 URL
不匹配,match
则为 null
,这容许你动态调整你的 UI
界面,基于路线是否匹配,若是路线匹配咱们则添加一个 active
类。
<ul>
<ListItemLink to="/somewhere"/>
<ListItemLink to="/somewhere-else"/>
</ul>
const ListItemLink = ({ to, ...rest }) => (
<Route path={to} children={({ match }) => (
<li className={match ? 'active' : ''}>
<Link to={to} {...rest}/>
</li>
)}/>
)
复制代码
path: string
任何 path-to-regexp
能够解析的有效的 URL
路径
<Route path="/users/:id" component={User}/>
复制代码
exact: bool
若是为 true
,则只有在路径彻底匹配 location.pathname
时才匹配。
path | location.pathname | exact | matches? |
---|---|---|---|
/one | /one/two | true | no |
/one | /one/two | false | yes |
<Route exact path="/one" component={About}/>
复制代码
jsliang 我的经验:
exact
属性后,会彻底匹配路径;若是没有加,则二级路径也会匹配当前路径(例如 /timeline/book
)。<BrowserRouter>
<Route path="/" exact component={TimeLine}></Route>
<Route path="/timeline" component={TimeLine}></Route>
</BrowserRouter>
复制代码
extra
的值,从而判断是否须要加载某个组件。const Home = () => <div>Home</div>;
const App = () => {
const someVariable = true;
return (
<Switch>
{/* these are good */}
<Route exact path="/" component={Home} />
<Route
path="/about"
render={props => <About {...props} extra={someVariable} />}
/>
{/* do not do this */}
<Route
path="/contact"
component={props => <Contact {...props} extra={someVariable} />}
/>
</Switch>
);
};
复制代码
location: object
一个 <Route>
元素尝试其匹配 path
到当前的历史位置(一般是当前浏览器 URL)。可是,也能够经过location 一个不一样 pathname
的匹配。
sensitive: bool
若是路径区分大小写,则为 true
,则匹配。
path | location.pathname | sensitive | matches? |
---|---|---|---|
/one | /one | true | yes |
/One | /one | true | no |
/One | /one | false | yes |
<Route sensitive path="/one" component={About}/>
复制代码
渲染与该地址匹配的第一个子节点 <Route>
或者 <Redirect>
。
能够利用 <Switch>
作分组,即当有匹配时,匹配对应 path
对应的组件;若是没有匹配,则匹配 NotFound
页面。
<BrowserRouter>
<Header /> <Switch> <Route path="/" exact component={TimeLine}></Route> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </BrowserRouter>
复制代码
history
是一个包,在你安装 React Router 的时候,会做为它依赖包安装到项目中,因此你能够直接使用 history
中的属性和方法:
length
- (number
类型) history
堆栈的条目数action
- (string
类型) 当前的操做(push
, replace
, pop
)location
- (object
类型) 当前的位置。location
会具备如下属性:
pathname
- (string
类型) URL 路径search
- (string
类型) URL 中的查询字符串hash
- (string
类型) URL 的哈希片断state
- (object
类型) 提供给例如使用 push(path, state)
操做将location
放入堆栈时的特定 location
状态。只在浏览器和内存历史中可用push(path, [state])
- (function
类型) 在 history
堆栈添加一个新条目replace(path, [state])
- (function
类型) 替换在 history
堆栈中的当前条目go(n)
- (function
类型) 将 history
堆栈中的指针调整 n
goBack()
- (function
类型) 等同于 go(-1)
goForward()
- (function
类型) 等同于 go(1)
block(prompt)
- (function
类型) 阻止跳转随着应用的增加,代码包会随着生长。
到最后你会发现,你打包后的 js 文件大地太多离谱。
因此,咱们须要经过代码分割,依据不一样的路由,加载不一样的 js 文件。
npm i react-loadable -S
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';
const Loading = () => <div>Loading...</div>;
const Home = Loadable({
loader: () => import('./routes/Home'),
loading: Loading,
});
const About = Loadable({
loader: () => import('./routes/About'),
loading: Loading,
});
const App = () => (
<Router>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Router>
);
复制代码
npm run build
src/components/ScrollToTop/index.js
import { Component } from 'react';
import { withRouter } from 'react-router-dom';
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop);
复制代码
src/App.js
import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';
function App() {
return (
<Fragment> <BrowserRouter> <Header /> <ScrollToTop> <Switch> <Redirect from="/" to="/timeline" exact /> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </ScrollToTop> </BrowserRouter> </Fragment> ); } export default App; 复制代码
暂未实现
在项目中,咱们更但愿 React Router 和 React Redux 合并起来,这时候能够:
// before
export default connect(mapStateToProps)(Something)
// after
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Something))
复制代码
若是你纯粹过文档(官方文档,jsliang 的文档),你会以为毫无趣味、了无生趣、乏味、沉闷……
因此,jsliang 的学法是:开启了一个项目,边翻阅文档,边应用到项目中,并进行 Mark 标记,以便下次使用。
如此,该文档虽然完结了,可是仍未完结!完结的是我过完了官方文档,未完结的是 React Router 在我项目中可能有其余应用,须要我一一添加进来。
jsliang 广告推送:
也许小伙伴想了解下云服务器
或者小伙伴想买一台云服务器
或者小伙伴须要续费云服务器
欢迎点击 云服务器推广 查看!
jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于github.com/LiangJunron…上的做品创做。
本许可协议受权以外的使用权限能够从 creativecommons.org/licenses/by… 处得到。