引言
自从 React 16 发布后, React Router 也发布了第五个版本,更好的支持 React 16。
官方文档链接:reacttraining.com/react-route…
快速开始
要在一个 web app 中使用 react router, 首先你需要搭建一个 React web app,我们推荐 creat react app。它是一个非常流行的工具,并且很好的支持 React Router。
首先,安装 create-react-app 并用它创建一个新的项目。
npm install -g create-react-app
create-react-app demo-app
cd demo-app
安装
你可以用 npm 或者 yarn 安装 React Router,由于我们在构建一个web app,所以我们在这个文档中使用 react-router-dom
npm install react-router-dom
接下来,赋值粘贴下面的任意一个列子到项目的/App.js 中。
例子 1:基本路由示例
在这个例子中,路由器处理了3个页面: home、about、user。当你点击不同的Link时,路由器会渲染与之匹配的Route
注意: Link 标签会使用真实的 href 渲染 a 标签,所以使用键盘进行导航或者屏幕阅读器的人也可以使用这个应用。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
{/* A <Switch> looks through its children <Route>s and
renders the first one that matches the current URL. */}
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
例子 2:嵌套路由
这个例子展示了嵌套路由如何使用。 /topics 路由加载 Topics 组件,这个组件可以渲染与路径上的 /:topicId 对应的任何其他Route。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Topics() {
let match = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
{/* The Topics page has its own <Switch> with more routes
that build on the /topics URL path. You can think of the
2nd <Route> here as an "index" page for all topics, or
the page that is shown when no topic is selected */}
<Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route>
<Route path={match.path}>
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
function Topic() {
let { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>;
}
继续加油!
希望这些例子可以帮助你对使用React router 创建应用找到一点感觉,继续阅读以了解有关 React router 中主要组件的更多信息!
主要组件
React Router中的组件主要分为三类:
- 路由器,例如 BrowserRouter 和 HashRouter
- 路由匹配器: 例如Route和Switch
- 导航:例如Link, NavLink, and Redirect
我们也喜欢将导航组件称为"route changers"。
注意: 在 web app 中,所有这些组件需要从
react-router-dom中引入。
import { BrowserRouter, Route, Link } from "react-router-dom";
路由器
每个 React Router 应用程序的核心应该是路由器组件。对于 web 项目,react-router-dom 提供BrowserRouter和HashRouter路由器。两者之间的主要区别是它们存储URL和与Web服务器通信的方式。
- BrowserRouter 使用常规URL路径,创建一个像example.com/some/path这样真实的 URL ,但是他们要求正确的配置服务器。具体来说,您的 web 服务器需要在所有由 React Router 客户端管理的 URL 上处理相同的页面。Create React App在开发中即开即用地支持此功能,并附带有关如何配置生产服务器的说明。
- HashRouter 将当前位置存储在URL的哈希部分中,因此URL看起来类似于example.com/#/your/page…
要使用路由器,只需要确保将其渲染在根目录下即可,通常,您会将顶级的App元素包装在路由器下,如下所示:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
function App() {
return <h1>Hello React Router</h1>;
}
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
路由匹配器
有两种路由匹配组件:Switch 和 Route。 当渲染Switch 组件时,它将搜索它的Route子元素,以查找路径与当前URL匹配的元素,它将呈现找到的第一个Route并忽略所有的其他路由。这意味着您应该将包含更多特定路径的Route放在不那么特定的路由之前。
如果没有匹配的Route,Switch将什么都不会渲染(null)。
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
function App() {
return (
<div>
<Switch>
{/* 如果当前URL是/ about,则呈现此路由而其余的被忽略 */}
<Route path="/about">
<About />
</Route>
{/* 请注意这两个路由的顺序。更具体的path =“ / contact /:id”在path =“ / contact”之前,因此查看单个联系人时,这个路线将被渲染 */}
<Route path="/contact/:id">
<Contact />
</Route>
<Route path="/contact">
<AllContacts />
</Route>
{/*
如果先前的路线都不提供任何东西,这条路线充当后备路线。
重要提示:路径为'/'的路线将始终匹配URL,这就是为什么我们把它放在最后。
*/}
<Route path="/">
<Home />
</Route>
</Switch>
</div>
);
}
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById("root")
);
需要注意的一点是 Route path匹配的是URL的开头而不是整个URL,所以<Route path="/"> 会始终与URL匹配,所以我们通常将这个Route放在<Switch>的最后,还有一个解决方案就是使用<Route exact path="/">,使用 exact 将使Route匹配整条 URL 而不仅仅是开头。
注意:尽管React Router 确实支持在
<Switch>之外渲染<Route>元素,但是5.1版本开始,我们建议您改用useRouteMatch钩子。此外,我们不建议您呈现不带路径的<Route>,而是建议您使用钩子来访问所需的任何变量。
导航
React Router提供了一个<Link>组件来在您的应用程序中创建链接。无论在何处呈现<Link>,锚点都将呈现在HTML文档中。
<Link to="/">Home</Link>
// <a href="/">Home</a>
<NavLink>是<Link>的一种特殊类型,当其prop与当前位置匹配时,可以给它设置一个activeClassName的样式。
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// When the URL is /react, this renders:
// <a href="/react" className="hurray">React</a>
// When it's something else:
// <a href="/react">React </a>
任何时候要强制导航,你都可以使用<Redirect>,当呈现<Redirect>时,将根据 prop 的 to 值进行导航。
<Redirect to="/login" />
代码分割
web app的一个重要有点就是,我们不必让用户下载整个应用即可使用,您可以将代码分割是为增量下载app。为此,我们将使用 webpack,
@babel/plugin-syntax-dynamic-import和 loadable-components.
webpack内置了对动态导入的支持;但是,如果您使用的是Babel(例如,将JSX编译为JavaScript),则需要使用@ babel / plugin-syntax-dynamic-import插件。这是仅语法的插件,这意味着Babel不会进行任何其他转换。该插件仅允许Babel解析动态导入,因此webpack可以将它们捆绑为代码拆分。您的.babelrc应该如下所示:
{
"presets": ["@babel/preset-react"],
"plugins": ["@babel/plugin-syntax-dynamic-import"]
}
loadable-components是用于通过动态导入加载组件的库。它自动处理各种边缘情况,并使代码拆分变得简单,下面是有关如何使用loadable-components的示例:
import loadable from "@loadable/component";
import Loading from "./Loading.js";
const LoadableComponent = loadable(() => import("./Dashboard.js"), {
fallback: <Loading />
});
export default class LoadableDashboard extends React.Component {
render() {
return <LoadableComponent />;
}
}
只需使用LoadableDashboard(或任何您命名的组件),当您在应用程序中使用它时,它将自动加载并呈现。fallback 是一个占位符组件,用于在加载实际组件时显示。
完整的文档在这里
滚动复原
在早期版本的React Router中,我们提供了对滚动恢复的开箱即用的支持,希望本文档可以帮助您从滚动条和路由中获得所需的信息! 浏览器已经开始以自己的history.pushState处理滚动恢复,其方式与通过普通浏览器导航进行滚动恢复的方式相同。它已经可以在Chrome浏览器中使用,而且非常棒。这里是滚动恢复规范。
由于浏览器已经开始处理“默认情况”,并且应用具有不同的滚动需求(例如本网站),因此我们不提供默认滚动管理功能。本指南可以帮助您实现所需要的滚动功能。
滚动至顶部
在大多数情况下,您所需要做的只是“滚动到顶部”,因为您有一个较长的内容页面,该页面在导航到该页面时始终保持向下滚动。使用<ScrollToTop>组件可以轻松处理此问题,该组件将在每次导航时向上滚动窗口:
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
如果您尚未使用 React 16.8,则可以使用React.Component子类执行相同的操作:
import React from "react";
import { withRouter } from "react-router-dom";
class ScrollToTop extends React.Component {
componentDidUpdate(prevProps) {
if (
this.props.location.pathname !== prevProps.location.pathname
) {
window.scrollTo(0, 0);
}
}
render() {
return null;
}
}
export default withRouter(ScrollToTop);
然后将其放在您应用的顶部。
function App() {
return (
<Router>
<ScrollToTop />
<App />
</Router>
);
}
如果你有一个 tab 接口连接到路由器,那么在切换tab的时候,您可能不想滚动到顶部,你可以在特定的位置使用使用<ScrollToTopOnMount>
import { useEffect } from "react";
function ScrollToTopOnMount() {
useEffect(() => {
window.scrollTo(0, 0);
}, []);
return null;
}
// Render this somewhere using:
// <Route path="..." children={<LongContent />} />
function LongContent() {
return (
<div>
<ScrollToTopOnMount />
<h1>Here is my long content page</h1>
<p>...</p>
</div>
);
}
同样,如果您还没有运行React 16.8,则可以使用React.Component子类执行相同的操作:
import React from "react";
class ScrollToTopOnMount extends React.Component {
componentDidMount() {
window.scrollTo(0, 0);
}
render() {
return null;
}
}
// Render this somewhere using:
// <Route path="..." children={<LongContent />} />
class LongContent extends React.Component {
render() {
return (
<div>
<ScrollToTopOnMount />
<h1>Here is my long content page</h1>
<p>...</p>
</div>
);
}
}
通用解决方案
对于通用解决方案(以及哪些浏览器已原生支持),我们谈论的是两件事:
- 向上滚动导航,这样就不会启动滚动到底部的新屏幕
- 恢复窗口的滚动位置和在“后退”和“前进”点击上溢出的元素(不是 Link 点击)。
在这一点上,我们希望提供一个通用的API。这就是我们想要实现的:
<Router>
<ScrollRestoration>
<div>
<h1>App</h1>
<RestoredScroll id="bunny">
<div style={{ height: "200px", overflow: "auto" }}>
I will overflow
</div>
</RestoredScroll>
</div>
</ScrollRestoration>
</Router>
首先,ScrollRestoration将在导航时向上滚动窗口。其次,它将使用location.key将窗口滚动位置和RestoredScroll组件的滚动位置保存到sessionStorage。然后,在ScrollRestoration或RestoredScroll组件 mount时,它们可以从sessionStorage查找其位置。
棘手的部分是当你不希望窗口滚动被管理的时候,如何定义一个 "退出" 的api,例如,如果您在页面内容中浮动了一些标签导航,则可能不想滚动到顶部。
当我们得知Chrome现在可以为我们管理滚动位置,并意识到不同的应用程序将具有不同的滚动需求时,我们有点迷失了我们需要提供某些东西的信念,尤其是当人们只想滚动到顶部时。
基于此,我们不再有足够的力气自己完成工作(就像您一样,我们的时间有限!)。但是,我们很乐意为有志于实施通用解决方案的任何人提供帮助。一个可靠的解决方案甚至可以存在于项目中。如果您开始使用它,请与我们联系:)
Philosophy
本指南的目的是说明使用React Router时要具有的思维模型。我们称之为“动态路由”,它与您可能更熟悉的“静态路由”完全不同
静态路由
如果您使用过Rails,Express,Ember,Angular等,那您已经使用过了静态路由。 在这些框架中,您需要在进行任何渲染之前将路由声明为应用初始化的一部分。 React Router pre-v4也是静态的(大部分情况下)。让我们看一下如何快速配置路由:
// Express Style routing:
app.get("/", handleIndex);
app.get("/invoices", handleInvoices);
app.get("/invoices/:id", handleInvoice);
app.get("/invoices/:id/edit", handleInvoiceEdit);
app.listen();
请注意在应用监听之前如何声明路由。我们使用的客户端路由器也是相似的。在Angular中,您先声明路线,然后在渲染之前将其导入顶级AppModule:
// Angular Style routing:
const appRoutes: Routes = [
{
path: "crisis-center",
component: CrisisListComponent
},
{
path: "hero/:id",
component: HeroDetailComponent
},
{
path: "heroes",
component: HeroListComponent,
data: { title: "Heroes List" }
},
{
path: "",
redirectTo: "/heroes",
pathMatch: "full"
},
{
path: "**",
component: PageNotFoundComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)]
})
export class AppModule {}
Ember有一个常规的route.js文件,该版本会为您读取并导入到应用程序中。同样,这是在您的应用渲染之前发生的。
// Ember Style Router:
Router.map(function() {
this.route("about");
this.route("contact");
this.route("rentals", function() {
this.route("show", { path: "/:rental_id" });
});
});
export default Router;
尽管API不同,但它们都共享“静态路由”模型。 React Router也跟进了直到v4。 为了成功使用React Router,您需要忘记上面这些内容!
动态路由
当我们讨论动态路由时,我们是指在您的应用渲染时发生的路由,而不是在运行中的应用之外配置或约定的。
这意味着几乎所有内容都是React Router中的一个组件。下面是对该API的60秒回顾,以了解其工作原理:
首先,为您要定位的环境获取一个Router组件,并将其呈现在应用程序的顶部。
// react-dom (what we'll use here)
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
el
);
接下来,获取链接组件以链接到新位置:
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
)
最后,渲染一个Route以在用户访问/ dashboard时显示一些UI。
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
<div>
<Route path="/dashboard" component={Dashboard} />
</div>
</div>
);
该 Route 将呈现<Dashboard {... props} />,其中 props 是路由器特定的东西,比如 { match, location, history }。如果用户不在/ dashboard上,则Route将呈现null。
嵌套路由
许多路由器具有“嵌套路由”的概念。如果您使用了v4之前的React Router版本,那么您也会知道它也是如此,当您从静态路由配置转移到动态渲染的路由时,如何“嵌套路由”?
const App = () => (
<BrowserRouter>
{/* here's a div */}
<div>
{/* here's a Route */}
<Route path="/tacos" component={Tacos} />
</div>
</BrowserRouter>
);
// when the url matches `/tacos` this component renders
const Tacos = ({ match }) => (
// here's a nested div
<div>
{/* here's a nested Route,
match.url helps us make a relative path */}
<Route path={match.url + "/carnitas"} component={Carnitas} />
</div>
);
就像div一样,Route只是一个组件。因此,要嵌套一个Route或一个div,您只需像嵌套div一样就可以了。
再进一步学习更复杂的内容吧!
响应式路由
考虑到一个用户导航至 /invoices,您的应用程序适应不同的屏幕尺寸,他们屏幕比较小的时候,你只能向他们展示单据清单和跳转单据的dashboard的链接,所以他们可以从这里在跳转到更深的地方。
Small Screen
url: /invoices
+----------------------+
| |
| Dashboard |
| |
+----------------------+
| |
| Invoice 01 |
| |
+----------------------+
| |
| Invoice 02 |
| |
+----------------------+
| |
| Invoice 03 |
| |
+----------------------+
| |
| Invoice 04 |
| |
+----------------------+
在更大的屏幕上,我们希望显示一个主从视图,该视图的左侧是导航,而dashbord 或 特定的单据则显示在右侧。
Large Screen
url: /invoices/dashboard
+----------------------+---------------------------+
| | |
| Dashboard | |
| | Unpaid: 5 |
+----------------------+ |
| | Balance: $53,543.00 |
| Invoice 01 | |
| | Past Due: 2 |
+----------------------+ |
| | |
| Invoice 02 | |
| | +-------------------+ |
+----------------------+ | | |
| | | + + + | |
| Invoice 03 | | | + | | | |
| | | | | | + | + | |
+----------------------+ | | | | | | | | |
| | +--+-+--+--+--+--+--+ |
| Invoice 04 | |
| | |
+----------------------+---------------------------+
现在暂停一分钟,思考一下 /invoices 路径如何适配两种屏幕大小,或者更大的屏幕呢,他还能适用吗?我们应该在右边放什么呢?
url: /invoices
+----------------------+---------------------------+
| | |
| Dashboard | |
| | |
+----------------------+ |
| | |
| Invoice 01 | |
| | |
+----------------------+ |
| | |
| Invoice 02 | ??? |
| | |
+----------------------+ |
| | |
| Invoice 03 | |
| | |
+----------------------+ |
| | |
| Invoice 04 | |
| | |
+----------------------+---------------------------+
在大屏幕上,/invoices 不是有效的路径,但在小屏幕上是,为了使事情变得更有趣,请考虑使用大型手机的人。他们可能会纵向查看/invoices,然后将手机旋转至横向。突然,我们有足够的空间来显示主从界面,因此您应该立即进行重定向!
React Router先前版本的静态路由并没有真正解决这个问题的方法。但是,当路由是动态的时,您可以声明性地组合此功能。如果您开始将路由视为一种UI,而不是静态配置,那么您的直觉将引导您进入以下代码:
const App = () => (
<AppLayout>
<Route path="/invoices" component={Invoices} />
</AppLayout>
);
const Invoices = () => (
<Layout>
{/* always show the nav */}
<InvoicesNav />
<Media query={PRETTY_SMALL}>
{screenIsSmall =>
screenIsSmall ? (
// small screen has no redirect
<Switch>
<Route
exact
path="/invoices/dashboard"
component={Dashboard}
/>
<Route path="/invoices/:id" component={Invoice} />
</Switch>
) : (
// large screen does!
<Switch>
<Route
exact
path="/invoices/dashboard"
component={Dashboard}
/>
<Route path="/invoices/:id" component={Invoice} />
<Redirect from="/invoices" to="/invoices/dashboard" />
</Switch>
)
}
</Media>
</Layout>
);
当用户将手机从纵向旋转到横向时,此代码将自动将其重定向到 /invoices/dashboard。 有效路径会根据用户手中移动设备的动态性质而变化。
这只是一个例子,我们总结以下建议:为了使您的直觉与React Router的直觉相符,请考虑组件而不是静态路由。考虑一下如何使用React的声明式可组合性解决问题,因为几乎每个“ React Router问题”都可能是“ React问题”。
Hooks
React Router带有一些 hooks,可让您访问路由器的状态并从组件内部执行导航。
请注意:您需要使用React> = 16.8才能使用这些钩子
- useHistory
- useLocation
- useParams
- useRouteMatch
useHistory
useHistory hook 使您可以访问可用于导航的历史记录实例。
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
useLocation hook 返回代表当前URL的 location 对象。你可以把它当成一个 useState hook,只要URL更改,它就会返回一个新位置。如果你希望每次加载新页面的时候都使用 web 分析工具除法新的“页面浏览”事件,这个 hook 将会非常有用。
如下示例:
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
useParams返回URL参数的键/值对的对象。使用它来访问当前<Route>的match.params。
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
useRouteMatch hook 以与<Route>相同的方式匹配当前URL。它主要用于在无需实际呈现<Route>即可访问匹配数据的需求。
下面这个例子:
import { Route } from "react-router-dom";
function BlogPost() {
return (
<Route
path="/blog/:slug"
render={({ match }) => {
// Do whatever you want with the match...
return <div />;
}}
/>
);
}
可以替换为:
import { useRouteMatch } from "react-router-dom";
function BlogPost() {
let match = useRouteMatch("/blog/:slug");
// Do whatever you want with the match...
return <div />;
}
BrowserRouter
使用 HTML5 history API(pushState,replaceState和popstate事件) 使 UI 与 URL 保持同步的 Router。
<BrowserRouter
basename={optionalString}
forceRefresh={optionalBool}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App />
</BrowserRouter>
basename:string
所有路径的基本URL。如果您的应用是通过服务器上的子目录提供的,则需要将其设置为子目录。格式正确的基本名称应以斜杠开头,但不能以斜杠结尾。
<BrowserRouter basename="/calendar" />
<Link to="/today"/> // renders <a href="/calendar/today">
getUserConfirmation: func
跳转路由前的确认函数。默认为使用window.confirm。
<BrowserRouter
getUserConfirmation={(message, callback) => {
// this is the default behavior
const allowTransition = window.confirm(message);
callback(allowTransition);
}}
/>
forceRefresh: bool
如果设为true,在路由跳转时将整页刷新。一般情况下,只有在不支持 HTML5 history API 的浏览器中使用此功能。
<BrowserRouter forceRefresh={true} />
keyLength: number
location.key的长度,默认为6。
<BrowserRouter keyLength={12} />
children: node
要呈现的子元素。
注意:在 React < 16的版本中,你必须使用 单个子元素,因为render方法不能返回多个元素,你可以将他们包裹在额外的div元素中。
HashRouter
<Router>使用URL的哈希部分(即window.location.hash)使UI与URL保持同步
重要提示:hash history 不支持location.key 或者 location.state。在之前的版本中,我们试图shim这种行为,但存在一些无法解决的极端情况。任何需要此行为的代码或插件都将无法使用。由于此技术仅用于支持旧版浏览器,因此建议您将服务器配置为与
<BrowserHistory>一起使用。
<HashRouter
basename={optionalString}
getUserConfirmation={optionalFunc}
hashType={optionalString}
>
<App />
</HashRouter>
basename: string
所有路径的基本URL。basename 应以斜杠开头,但不能以斜杠结尾。
<HashRouter basename="/calendar"/>
<Link to="/today"/> // renders <a href="#/calendar/today">
getUserConfirmation: func
跳转路由前的确认函数。默认为使用window.confirm。
<HashRouter
getUserConfirmation={(message, callback) => {
// this is the default behavior
const allowTransition = window.confirm(message);
callback(allowTransition);
}}
/>
hashType: string
用于window.location.hash的编码类型。可用值为:
- "slash"- # 后有一个斜线,例如: #/ 或 #/sunshine/lollipops
- "noslash"-# 后面没有斜线,例如:# 或 #sunshine/lollipops
- "hashbang"-Google 风格的 ajax crawlable,例如 #!/ 和 #!/sunshine/lollipops
默认为 "slash"
children:node
要呈现的单个子元素
##Link 为你的应用提供声明式的、可访问的导航链接。
<Link to="/about">About</Link>
to: string
链接地址的字符串表示形式,通过 pathname + search + hash 创建
<Link to='/courses?sort=name' />
to: object
to 可以包含以下属性:
- pathname: 要跳转的路径
- search: URL中query参数的字符串形式
- hash:URL中的hash部分,例如:#a-hash.
- state:存储到 location 中的额外状态数据
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: {
fromDashboard: true
}
}} />
to:function
以当前位置为参数传递给该函数,该函数以字符串或对象的形式返回目标路径。
<Link to={location => ({ ...location, pathname: "/courses" })} />
<Link to={location => `${location.pathname}?sort=name`} />
replace:bool
replace 为 true 时,点击链接将会在历史记录中替换 当前页面,而不是添加一个新的页面。
<Link to="/courses" replace />
innerRef: function
提示:从React Router 5.1开始,如果您使用的是React 16,就不需要这个参数了。因为我们已经将 ref 转发给了底层的 a 标签,所以您可以直接使用 ref。
允许访问组件的底层引用。
const refCallback = node => {
// node 指向最终挂载的 DOM 元素,在卸载时为 null
}
<Link to="/" innerRef={refCallback} />
innerRef: RefObject
同上
使用React.createRef获取组件的底层引用。
let anchorRef = React.createRef()
<Link to="/" innerRef={anchorRef} />
其他
你也可以传递一些其他的a标签的属性,例如: title, id, className等
NavLink
NavLink 是 Link 标签的一个特殊版本,当匹配到当前URL时,可以为渲染的元素添加特定的样式属性。
<NavLink to="/about">About</NavLink>
activeClassName: string
当元素处于选中状态时提供的类,默认状态是active。将与 className 合并。
<NavLink to="/faq" activeClassName="selected">
FAQs
</NavLink>
activeStyle: object
为选中状态提供的样式
<NavLink
to="/faq"
activeStyle={{
fontWeight: "bold",
color: "red"
}}
>
FAQs
</NavLink>
exact:bool
当exact 为 true 时,选中状态提供的类或样式仅在路径完全匹配时提供。
<NavLink exact to="/profile">
Profile
</NavLink>
strict:bool
当 strict 为 true 时,路径上的斜杠也将作为路径是否当前网址匹配的判断条件之一。查看更多信息,参见Route strict文档
<NavLink strict to="/events/">
Events
</NavLink>
isActive: func
添加额外的逻辑来判断当前链接是否处于选中状态。如果需要更多的验证来判断链接的路径名是否与当前URL匹配,可使用这种方法。
<NavLink
to="/events/123"
isActive={(match, location) => {
if (!match) {
return false;
}
// only consider an event active if its event id is an odd number
const eventID = parseInt(match.params.eventID);
return !isNaN(eventID) && eventID % 2 === 1;
}}
>
Event 123
</NavLink>
location: object
isActive比较当前历史记录位置(通常是当前浏览器URL)。要与其他位置进行比较,可以传递 location 属性
aria-current: string
aria-current 属性的值应用在active 的 link 上。有效值为:
- "page" - 用来表示一组分页链接中的链接
- "step" - 用来表示步骤指示器中基于步骤过程的链接
- "location" - 用来表示突出展示流程图中的当前部分的图像
- "date" - 用来表示日历中的当前日期
- "time" - 用来表示时间表中的当前时间
- "true" - 用来表示当前 NavLink 是否处于激活状态
默认为 page
Prompt
用于在离开页面之前提示用户。当您的应用程序进入应防止用户离开的状态时(例如,表单已被半填满),使用<Prompt>
<Prompt
when={formIsHalfFilledOut}
message="Are you sure you want to leave?"
/>
message: string
页面离开前的提示语
<Prompt message="Are you sure you want to leave?" />
message: func
当用户准备跳转到下一个页面时调用,返回一个用于提示的字符串或者return true 允许直接跳转。
<Prompt
message={location =>
location.pathname.startsWith("/app")
? true
: `Are you sure you want to go to ${location.pathname}?`
}
/>
when: bool
通过when={true}或when={false}来允许或阻止进行相应的跳转,这样就可以不用判断是否渲染这个组件了。
<Prompt when={formIsHalfFilledOut} message="Are you sure?" />
MemoryRouter
将“ URL”的历史记录保留在内存中(不读取或写入地址栏)的<Router>。在测试和非浏览器环境(例如React Native)中很有用
<MemoryRouter
initialEntries={optionalArray}
initialIndex={optionalNumber}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App />
</MemoryRouter>
initialEntries: array
历史堆栈中的一系列位置信息。这些可能是带有 {pathname, search, hash, state} 的完整位置对象或简单的字符串 URL。
<MemoryRouter
initialEntries={[ '/one', '/two', { pathname: '/three' } ]}
initialIndex={1}
>
<App/>
</MemoryRouter>
initialIndex: number
initialEntries 数组中的初始位置索引。
getUserConfirmation: func
用于确认导航的函数。当 <MemoryRouter> 直接与 <Prompt> 一起使用时,你必须使用此选项。
keyLength: number
location.key 的长度,默认为 6。
children: node
要呈现的单个子元素(组件)
Redirect
渲染一个Redirect 组件将跳转至一个新的地址,新地址将覆盖历史记录中的当前条目。就像服务端的重定向。
<Route exact path="/">
{loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>
to:string
重定向到的地址,可以是path-to-regexp支持的所有有效路径。to中使用的所有URL参数必须由from提供。
<Redirect to="/somewhere/else" />
to:object
同上
<Redirect
to={{
pathname: "/login",
search: "?utm=your+face",
state: { referrer: currentLocation }
}}
/>
state 对象可以在重定向到的组件中通过 this.props.location.state 进行访问。而 referrer 键(不是特殊名称)将通过路径名 /login 指向的登录组件中的 this.props.location.state.referrer 进行访问。
push:bool
如果push 为true,重定向将会向历史记录中推入新的条目而不是替换当前条目。
<Redirect push to="/somewhere/else" />
from:string
要进行重定向的路径名。可以是path-to-regexp支持的所有有效路径。所有匹配的url的参数都会提供给to指定的重定向的地址,to 未使用的其它参数将被忽略。
提示:from 参数仅支持在 Switch 组件内的 Redirect组件使用,具体请参考:Switch children
<Switch>
<Redirect from='/old-path' to='/new-path' />
<Route path='/new-path'>
<Place />
</Route>
</Switch>
// Redirect with matched parameters
<Switch>
<Redirect from='/users/:id' to='/users/profile/:id'/>
<Route path='/users/profile/:id'>
<Profile />
</Route>
</Switch>
exact:bool
是否精准匹配。
提示:仅支持在Switch 组件内渲染 Redirect 组件时,结合from使用exact,具体请参考:Switch children
<Switch>
<Redirect exact from="/" to="/home" />
<Route path="/home">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
strict:bool
是否严格模式
提示:仅支持在Switch 组件内渲染 Redirect 组件时,结合from使用严格匹配,具体请参考:Switch children
Route
路由组件可能是React Router中了解和学习中使用的最重要的组件。他的最基本的职责是在其路径与当前URL匹配时呈现某些UI。
思考下面的代码:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
ReactDOM.render(
<Router>
<div>
<Route exact path="/">
<Home />
</Route>
<Route path="/news">
<NewsFeed />
</Route>
</div>
</Router>,
node
);
如果当前路径是:/,那么 UI的结构将类似于:
<div>
<Home />
<!-- react-empty: 2 -->
</div>
如果当前的路径是:/news,那么UI的结构将类似于:
<div>
<!-- react-empty: 1 -->
<NewsFeed />
</div>
其中 react-empty 注释只是 React 空渲染的实现细节。但对于我们的目的而言,它是有启发性的。路由始终在技术上被“渲染”,即使它的渲染为空。只要应用程序的位置匹配 <Route> 的 path,你的组件就会被渲染。
Route render methods
建议使用的 Route 渲染方式是使用子元素,就像上面的例子上展示的。但是还是有一些其他的方式可用于Router渲染。提供这些方式主要是为了支持引用hooks之前版本的路由器构建的应用程序。
- Route component
- Route render
- Route children
在不同的情况下使用不同的方式。在指定的 中,你应该只使用其中的一种。请参阅下面的解释,了解为什么有三个选项。
Route props
所有的渲染方式都会提供相同的三个路由属性。
- match
- location
- history
component
React component 仅当路径匹配时才会渲染。它将会与route props一起渲染。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
// All route props (match, location and history) are available to User
function User(props) {
return <h1>Hello {props.match.params.username}!</h1>;
}
ReactDOM.render(
<Router>
<Route path="/user/:username" component={User} />
</Router>,
node
);
当你使用component(而不是render 或 children)时,Router 将根据指定的组件,使用 React.createElement 创建一个新的 React 元素。这意味着,如果你向 component 提供一个内联函数,那么每次渲染都会创建一个新组件。这将导致现有组件的卸载和新组件的安装,而不是仅仅更新现有组件。当使用内联函数进行内联渲染时,请使用 render 或 children(见下文)。
render:func
使用 render 可以方便地进行内联渲染和包装,而无需进行上文解释的不必要的组件重装。
你可以传入一个函数,以在位置匹配时调用,而不是使用 component 创建一个新的 React 元素。render 渲染方式接收所有与 component 方式相同的 route props。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
// convenient inline rendering
ReactDOM.render(
<Router>
<Route path="/home" render={() => <div>Home</div>} />
</Router>,
node
);
// wrapping/composing
// You can spread routeProps to make them available to your rendered Component
function FadingRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={routeProps => (
<FadeIn>
<Component {...routeProps} />
</FadeIn>
)}
/>
);
}
ReactDOM.render(
<Router>
<FadingRoute path="/cool" component={Something} />
</Router>,
node
);
警告:
<Route component>优先于<Route render>,因此不要在同一个<Route>中同时使用两者。
children:func
有些情况下,不管路径是否与位置匹配,你都需要去渲染一些东西,在这种情况下,你可以使用 childen prop,除了不论是否匹配它都会被调用以外,它的工作原理与 render 完全一样。
children 属性与 component 和 render 属性接收相同的 route props, 除法路由与路径不匹配,不匹配时 match 为 null。它允许你根据路由是否匹配动态的调整你的UI。如下所示,如果路线匹配,我们会添加一个激活类。
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Link,
Route
} from "react-router-dom";
function ListItemLink({ to, ...rest }) {
return (
<Route
path={to}
children={({ match }) => (
<li className={match ? "active" : ""}>
<Link to={to} {...rest} />
</li>
)}
/>
);
}
ReactDOM.render(
<Router>
<ul>
<ListItemLink to="/somewhere" />
<ListItemLink to="/somewhere-else" />
</ul>
</Router>,
node
);
它对动画也很有用:
Route
children={({ match, ...rest }) => (
{/* Animate will always render, so you can use lifecycles
to animate its child in and out */}
<Animate>
{match && <Something {...rest}/>}
</Animate>
)}
/>
警告:Route component 和 Route render 优先于 Route children,因此不要在同一个 Route 中同时使用多种。
path:string | string[]
可以是 path-to-regexp 能够理解的任何有效的 URL 路径。
<Route path="/users/:id" component={User} />
<Route path={["/users/:id", "/profile/:id"]}>
<User />
</Route>
没有 path 属性的 Route 将会一直被匹配。
exact:bool
当为true时,只有在 path 完全匹配 location.pathname 时才匹配。
<Route exact path="/one" component={OneComponent} />
| path | location.pathname | exact | matches? |
|---|---|---|---|
| /one | /one/two | true | no |
| /one | /one/two | false | yes |
strict:bool
如果为 true,则具有尾部斜杠的 path 仅与具有尾部斜杠的 location.pathname 匹配。当 location.pathname 中有附加的 URL 片段时,strict 就没有效果了。
<Route strict path="/one/">
<About />
</Route>
| path | location.pathname | matches? |
|---|---|---|
| /one/ | /one | no |
| /one/ | /one/ | yes |
| /one/ | /one/two/ | yes |
警告:strict可以用来强制location.pathname没有结尾的斜杠,但是要做到这一点,strict 和 exact 都必须为true。
<Route exact strict path="/one">
<About />
</Route>
| path | location.pathname | matches? |
|---|---|---|
| /one | /one | yes |
| /one | /one/ | no |
| /one | /one/two | no |
sensitive: bool
如果为 true,进行匹配时将区分大小写。
<Route sensitive path="/one" component={OneComponent} />
| path | location.pathname | sensitive | matches? |
|---|---|---|---|
| /one | /one | true | yes |
| /One | /one | true | no |
| /One | /one | false | yes |
Router
Router 是所有路由器组件的通用底层接口。通常,应用程序只会从以下高阶Router中选择一个作为代替:
- BrowserRouter
- HashRouter
- MemoryRouter
- NativeRouter
- StaticRouter
使用低阶 Router 的最常见用例是同步一个自定义历史记录与一个状态管理库,比如 Redux 或 Mobx。请注意,将 React Router 和状态管理库一起使用并不是必需的,它仅用于深度集成。
import { Router } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory';
const history = createBrowserHistory();
<Router history={history}>
<App />
</Router>
history: object
用于导航的历史记录对象。
import createBrowserHistory from 'history/createBrowserHistory';
const customHistory = createBrowserHistory();
<Router history={customHistory} />
children:node
要呈现的单个子元素
<Router>
<App />
</Router>
Switch
用于渲染与路径匹配的第一个子 Route 或 Redirect。
这与仅仅使用一系列 Route 有何不同?
Switch 只会渲染一个路由。相反,仅仅定义一系列 Route 时,每一个与路径匹配的 Route 都将包含在渲染范围内。考虑如下代码:
import { Route } from "react-router";
let routes = (
<div>
<Route path="/about">
<About />
</Route>
<Route path="/:user">
<User />
</Route>
<Route>
<NoMatch />
</Route>
</div>
);
如果 URL 是 /about,那么 About、User 和 NoMatch 将全部渲染,因为它们都与路径匹配。这是通过设计,允许我们以很多方式将 Route 组合成我们的应用程序,例如侧边栏和面包屑、引导标签等。
但是,有时候我们只想选择一个 Route 来呈现。比如我们在 URL 为 /about 时不想匹配 /:user(或者显示我们的 404 页面),这该怎么实现呢?以下就是如何使用 Switch 做到这一点:
import { Route, Switch } from "react-router";
let routes = (
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/:user">
<User />
</Route>
<Route>
<NoMatch />
</Route>
</Switch>
);
现在,当我们在 /about 路径时,Switch 将开始寻找匹配的 Route。我们知道,<Route. path="/about" /> 将会被正确匹配,这时 Switch 会停止查找匹配项并立即呈现 About。同样,如果我们在 /michael 路径时,那么 User 会呈现。
这对于动画转换也很有用,因为匹配的 Route 与前一个渲染位置相同。
let routes = (
<Fade>
<Switch>
{/* 这里只会渲染一个子元素 */}
<Route />
<Route />
</Switch>
</Fade>
);
let routes = (
<Fade>
{/* 这里会渲染2个子元素,一个可能是null,这将使得转换更加麻烦 */}
<Route />
<Route />
</Fade>
);
location: object
用于匹配子元素而不是当前历史位置(通常是当前的浏览器 URL)的 location 对象。
children: node
所有 Switch 的子元素都应该是 Route 或 Redirect。只有第一个匹配当前路径的子元素将被呈现。
Route 组件使用 path 属性进行匹配,而 Redirect 组件使用它们的 from 属性进行匹配。没有 path 属性的 Route 或者没有 from 属性的 Redirect 将始终与当前路径匹配。
当在 Switch 中包含 Redirect 时,你可以使用任何 Route 拥有的路径匹配属性:path、exact 和 strict。from 只是 path 的别名。
如果给 Switch 提供一个 location 属性,它将覆盖匹配的子元素上的 location 属性
import { Redirect, Route, Switch } from "react-router";
let routes = (
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<Users />
</Route>
<Redirect from="/accounts" to="/users" />
<Route>
<NoMatch />
</Route>
</Switch>
);
history
本文档中的"history" 和""history object"术语是指"history package"。 它是React Router仅有的两个主要依赖项之一(除了React本身),它提供了几种不同的实现来管理各种环境中JavaScript的会话历史记录。
下面几种术语也有涉及:
- “browser history” - 特定用于DOM的实现,在支持HTML5历史记录API的Web浏览器中很有用。
- “hash history” - 特定用于DOM的实现,适用于旧版网络浏览器
- “memory history” - 内存历史记录实现,可用于测试和非DOM环境(如React Native)
history object 通常具有以下属性和方法
- length -(number) 历史记录堆栈中的条目数
- action - (string) 当前操作类型(PUSH,REPLACE,POP)
- location(object) 当前位置对象,应该包括以下属性:
- pathname-(string) url中的路径
- search-(string) url中的 query
- hash-(string) url 中的 hash 片段
- state-(object) 例如 当进行push(path,state) 操作后, 当location 被推入堆栈时,特定位置的state属性将会被提供。
- push(path,[state]) - (function) 将一个新的历史条目推入历史堆栈。
- replace(path,[state])- (function) 在历史堆栈中替换当前历史条目
- go(n)-(function) 将历史记录堆栈中的指针移动n个条目
- goBack()-(function) 相当于 go(-1)
- goForward()-(function) 相当于 go(-1)
- block(prompt)-(funtion) 阻止跳转(详情the history doc)
history 是可变的
history 对象是可变的,所以我们不推荐从history.location 中获取 location,推荐从 props 中获取。这可以确保您对React的假设在生命周期挂钩中是正确的。例如:
class Comp extends React.Component {
componentDidUpdate(prevProps) {
// will be true
const locationChanged =
this.props.location !== prevProps.location;
// INCORRECT, will *always* be false because history is mutable.
const locationChanged =
this.props.history.location !== prevProps.history.location;
}
}
<Route component={Comp} />;
根据您使用的实现方式,可能还会显示其他属性。请参阅历史记录文档以获取更多详细信息。
loaction
位置表示应用程序当前位置,您希望其运行的位置,甚至是之前的位置。看起来像这样
{
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere',
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
路由器将在下面几个地方为您提供位置对象:
- Route component as this.props.location
- Route render as ({ location }) => ()
- Route children as ({ location }) => ()
- withRouter as this.props.location
它也可以在history.location上获取到,但您不应该使用从history.location上获取到的location对象,因为它是可变的。
位置对象永远不会发生突变,因此您可以在生命周期挂钩中使用它来确定何时进行导航,这对于数据获取和动画处理非常有用。
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
// navigated!
}
}
您可以在导航的各个位置中提供 location 对象而不是字符串,例如:Link to
通常情况下,您只需要传入字符串,但是如果您需要添加一些“位置状态”,只要应用返回到该特定位置,该状态便可用,则可以使用位置对象代替。如果您想基于导航历史而不是仅基于路径来区分UI,这将非常有用。
// usually all you need
<Link to="/somewhere"/>
// but you can use a location instead
const location = {
pathname: '/somewhere',
state: { fromDashboard: true }
}
<Link to={location}/>
<Redirect to={location}/>
history.push(location)
history.replace(location)
最后,你可以将location 传递给下面两个组件:
- Route
- Switch
这样可以防止他们在路由器状态下使用实际位置。这对于动画和待处理的导航很有用,或者在您想要诱使组件在与真实位置不同的位置进行渲染时,这很有用。
match
match 对象包含有关<Route path>如何与URL匹配的信息。匹配对象包含以下属性:
- params-(object) 从与路径的动态段相对应的URL解析的键/值对 如/:id
- isExact-(bool) 如果整个URL都匹配,则为true(无结尾字符)
- path-(string) 用于匹配的路径模式。用于构建嵌套的
<Route> - url-(string) URL的匹配部分。用于构建嵌套的
<Link>
可以在下面几个地方获取 match 对象:
- Route component as this.props.match
- Route render as ({ match }) => ()
- Route children as ({ match }) => ()
- withRouter as this.props.match
- matchPath as the return value
如果Route没有路径,那它将始终匹配,你会获得最接近的父项匹配。这个原理同样适用于 withRouter。
null matches
在 <Route path="/somewhere" children={({ match }) => ()} /> 中,即使 path 与当前位置不匹配,children 指定的内联函数也依然会被调用。这种情况下,match 为 null。能够在不匹配时依然呈现 <Route> 的内容可能很有用,但是这样会带来一些挑战。
解析 URL 的默认方式是将 match.url 字符串连接到 relative-path。
`${match.url}/relative-path`
如果你在 match 为 null 时尝试执行此操作,最终会出现 TypeError 错误。这意味着在使用 children 属性时尝试在 <Route> 内部连接 relative-path 是不安全的。
当您在产生空匹配对象的 <Route> 内部使用没有定义 path 的 <Route> 时,会出现类似但更微妙的情况。
// location.pathname = '/matches'
<Route path='/does-not-match' children={({ match }) => (
// match === null
<Route render={({ match: pathlessMatch }) => (
// pathlessMatch === ???
)} />
)} />
没有 path 的 <Route> 从它的父节点继承 match 对象。如果它的父匹配为 null,那么它的匹配也将为 null。这意味着:
任何子路由/子链接必须是绝对的
一个没有定义 path 的 <Route>,它的父匹配可以为 null,但它本身需要使用 children 来呈现内容。
matchPath
在正常的渲染周期之外,你可以使用和 <Route> 使用的相同的匹配代码,例如在服务器上呈现之前收集数据依赖关系。
import { matchPath } from 'react-router';
const match = matchPath('/users/123', {
path: '/users/:id',
exact: true,
strict: false
});
pathname
第一个参数是要匹配的路径名。如果您在服务器上通过 Node.js 使用,它将是 req.path。
props
第二个参数是匹配的属性,它们与<Route>接受的匹配属性相同:
{
path, // 例如 /users/:id
strict, // 可选,默认为 false
exact // 可选,默认为false
}
matchPath
你可以通过 withRouter 高阶组件访问 history 对象的属性和最近(UI 结构上靠的最近)的 <Route> 的 match 对象。当组件渲染时,withRouter 会将更新后的 match、location 和 history 传递给它。
import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
// 显示当前位置的 pathname 的简单组件
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>;
}
}
// 创建一个连接到 Router 的新组件(借用 redux 术语)
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
注意:withRouter 不会订阅位置更改 就像 React Redux 的 connect 对状态更改所做的更改。withRouter 是在位置更改从 <Router> 组件传播出去之后重新呈现。这意味着除非其父组件重新呈现,否则使用 withRouter 不会在路由转换时重新呈现。
静态方法和属性
封装组件的所有无反应的特定静态方法和属性都会自动复制到 connected 组件。
Component.WrappedComponent
被包装的组件被公开为返回组件上的静态属性 WrappedComponent,它可用于隔离测试组件等等。
// MyComponent.js
export default withRouter(MyComponent);
// MyComponent.test.js
import MyComponent from './MyComponent';
render(<MyComponent.WrappedComponent location={{...}} ... />);
wrappedComponentRef: func
一个将作为 ref 属性传递给包装组件的函数。
class Container extends React.Component {
componentDidMount() {
this.component.doSomething();
}
render() {
return (
<MyComponent wrappedComponentRef={c => this.component = c} />
)
}
}