react-router-dom@5.x官方文档翻译转载
Posted yomua
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react-router-dom@5.x官方文档翻译转载相关的知识,希望对你有一定的参考价值。
简介
这是我学习react-router-dom@5.1.2时,为了加深自己对react-router-dom的理解和帮助一些英文不好的同学,对官方文档进行了翻译,本人水平有限,如有理解和翻译错误,欢迎大家指正。官网地址
快速入门
要在web应用中开始使用React Router,您将需要一个React Web应用程序.如果您需要创建一个,我们建议您尝试Create React App。这是一个非常流行的工具,可与React Router很好地配合使用。
首先,安装create-react-app并使用它创建一个新项目。
安装
您可以使用npm或yarn从公共npm注册表中安装React Router。由于我们构建的是web app,因此在本指南中将使用react-router-dom。
npm install -g create-react-app // 全局安装 create-react-app
create-react-app demo-app // 创建一个react项目
cd demo-app // 进入react项目目录
npm install react-router-dom // 安装react-router-dom
接下来,将以下两个示例之一复制/粘贴到src/App.js中。
第一个示例:基本路由
在此示例中,路由器处理了3个“页面”:主页、关于页面和用户页面。当您点击不同的时,这个路由会渲染匹配的。
注意:其实最后渲染出来是一个有真实href的标签,因此使用键盘导航或屏幕阅读器的人也可以使用react-router-dom。
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Link } from \'react-router-dom\';
function Home(props) {
console.log(\'Home=>\', props);
return <h2>Home</h2>
}
function About(props) {
console.log(\'About=>\', props);
return <h2>About</h2>;
}
function Users(props) {
console.log(\'Users=>\', props);
return <h2>Users</h2>;
}
function App() {
return <BrowserRouter> <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>
{/* <Switch>通过查找所有的子<Route>并渲染与当前URL匹配的第一个<Route>的内容 */} <Switch>
<Route path={\'/about\'}>
<About />
</Route> <Route path={\'/users\'} children={<Users />}/>
<Route path={\'/\'}>
<Home />
</Route> </Switch> </div>
</BrowserRouter>
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
第二个示例:嵌套路由
此示例显示了嵌套路由的工作方式。路线/topics会加载Topics组件,在这个组件上的path:id值上有条件地渲染任何其他。
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Link, useRouteMatch, useParams } from \'react-router-dom\';
function Home(props) {
console.log(\'Home=>\', props);
return <h2>Home</h2>
}
function About(props) {
console.log(\'About=>\', props);
return <h2>About</h2>;
}
function Topic() {
let { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>
}
function Topics() {
const match = useRouteMatch();
console.log(\'match=>\', match);
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>
{/*
Topics页面有自己的<Switch>,其中包含更多的路线,建立在/topics路径之上
您可以将第二个<Route>视为所有主题的“索引”页面,或者当未选择任何主题时显示的页面
*/} <Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route> <Route path={match.path}> <h3>Please select a topic.</h3> </Route> </Switch>
</div>
);
}
function App() {
return <BrowserRouter> <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>
</BrowserRouter>
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
继续
希望这些示例能让您对使用React Router创建web app有点感觉。继续阅读可以了解有关React Router中主要组件的更多信息!
主要组件
React Router中的组件主要分为三类:
- 路由器,例如和
- 路由匹配器,例如和
- 导航,例如,和
在Web应用程序中使用的所有组件都应从react-router-dom导入。
路由器
每个React Router应用程序的核心应该是路由器组件。对于Web项目,react-router-dom提供和路由器。两者之间的主要区别在于它们存储URL和与Web服务器通信的方式。
- 使用常规URL路径。 这些通常是外观最好的网址,但它们要求您的服务器配置正确。 具体来说,您的Web服务器需要在所有由React Router客户端管理的URL上提供相同的页面。Create React App在开发中即开即用地支持此功能,并附带有关如何配置生产服务器的说明。
- 将当前位置存储在URL的哈希部分中,因此URL看起来类似于http://example.com/#/your/page。 由于哈希从不发送到服务器,因此这意味着不需要特殊的服务器配置。
要使用路由器,只需确保将其渲染在元素层次结构的根目录下即可。 通常,您会将顶级元素包装在路由器中,如下所示:
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。渲染时,它会搜索其子元素,以查找其路径与当前URL匹配的元素。当找到一个时,它将渲染该并忽略所有其他路由。这意味着您应该将包含更多特定路径(通常较长)的路径放在不那么特定路径之前。
如果没有匹配,则不渲染任何内容(null)。
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route } from \'react-router-dom\';
function App() {
return <div> <Switch> {/* 如果当前URL是/ about,那么将渲染此路由,而其余路由将被忽略 */} <Route path={\'/about\'}> <h2>About</h2> </Route> {/* 请注意这两个路由的顺序。 更具体的path="/contact/id"位于path="/contact"之前,因此在查看单个联系人时将显示这个<Route> */} <Route path={\'/contact/:id\'}> <h2>Contact</h2> </Route>
<Route path={\'/contact\'}>
<h2>AllContact</h2>
</Route>
{/*
如果先前的路由均未呈现任何内容,则此路由将充当后备路径。
重要提示:路径="/"的路线将始终匹配任何路径的URL,因为所有URL均以/开头。 所以这就是为什么我们把这这个<Route>放在最后
*/}
<Route path={\'/\'}> <h2>Home</h2> </Route>
</Switch>
</div>
}
ReactDOM.render(<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector(\'#root\'));
⚠️ 需要注意的重要一件事是匹配URL的开头,而不是整个开头。所以,将始终与任意一个URL匹配。因此,我们通常将此放在的最后。另一种可能的解决方案是使用确实与整个URL匹配的。exact属性表示精准匹配。
⚠️注意:尽管React Router确实支持在之外渲染元素,从5.1版开始,我们建议您改用useRouteMatch钩子。此外,我们不建议您渲染不带路径的,而是建议您使用钩子来访问您所使用的任何变量。
导航(或路线更改器)
React Router提供了一个组件来在您的应用程序中创建链接。 无论在何处渲染,锚点都将渲染在html文档中。
是的一种特殊类型,当其prop与当前位置匹配时,可以将其自身设置为“active”。
任何时候要强制导航,都可以渲染。渲染时,它将会使用其props进行导航
<Link to="/">Home</Link>
// <a href="/">Home</a>
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// 当URL为/react的时候, 渲染出来的以下内容:
// <a href="/react" className="hurray">React</a>
// 如果是其他URL,则渲染为:
// <a href="/react">React</a>
// 重定向到/login
<Redirect to="/login" />
NavLink例子:
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, NavLink } from \'react-router-dom\';
function NavigationApp() {
return <BrowserRouter>
<ul>
<li>
<NavLink to={\'/react\'}>React</NavLink>
</li>
<li>
<NavLink to={\'/redux\'}>redux</NavLink>
</li>
</ul>
<div>
<Switch>
<Route path={\'/react\'}>
<h1>React</h1>
</Route>
<Route path={\'/redux\'}>
<h1>Redux</h1>
</Route>
</Switch>
</div>
</BrowserRouter>
}
ReactDOM.render(<NavigationApp />, document.querySelector(\'#root\'));
服务器渲染
代码分割
网络应用的一个重要特色就是:我们无需让访问者下载整个应用程序即可使用,您可以将代码拆分视为增量下载应用程序。为此,我们将使用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是一个占位符组件,用于在加载实际组件时显示。
完整的文档在这里
代码拆分和服务器端渲染
loadable-components包含服务器端渲染的指南。
滚动还原
在早期版本的React Router中,我们提供了对滚动恢复的开箱即用的支持,从那以后人们一直在要求它。 希望本文档可以帮助您从滚动条和路由中获得所需的信息!
浏览器开始以自己的history.pushState处理滚动还原,其处理方式与使用普通浏览器导航时的处理方式相同。它已经可以在Chrome浏览器中使用,而且非常棒,这是滚动恢复规范。
由于浏览器开始处理“默认情况”,并且应用具有不同的滚动需求(例如本网站!),因此我们不提供默认滚动管理功能。 本指南应帮助您实现任何滚动需求。
滚动到顶部
在大多数情况下,您所需要做的只是“滚动到顶部”,因为您有一个较长的内容页面,该页面在导航到该页面时始终保持向下滚动。 使用组件可以轻松处理此问题,该组件将在每次导航时向上滚动窗口:
创建滚动到顶部组件:
import { useEffect } from \'react\';
import { useLocation } from \'react-router-dom\';
export default function ScrollToTop() {
const { pathname } = useLocation();
console.log(\'pathname=>\', pathname);
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);
然后在您的应用程序的顶部渲染它,但是要把它路由器下面:
import React from \'react\'
import ReactDOM from \'react-dom\';
import { BrowserRouter } from \'react-router-dom\';
import ScrollToTop from \'./ScrollToTop\'
function App() {
return <BrowserRouter>
<ScrollToTop/>
<h1>App</h1>
</BrowserRouter>
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
如果您将标签页接口连接到路由器,那么当他们切换标签页时,您可能不想滚动到顶部。 那么,您需要在的特定位置使用?
import { useEffect } from "react";
function ScrollToTopOnMount() {
useEffect(() => {
window.scrollTo(0, 0);
}, []);
return null;
}
// 使用以下代码将此内容渲染到某处:
// <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子类做同样的事情:
with a React.Component subclass:import React from "react";
class ScrollToTopOnMount extends React.Component {
componentDidMount() {
window.scrollTo(0, 0);
}
render() {
return null;
}
}
// 使用以下代码将此内容渲染到某处:
// <Route path="..." children={<LongContent />} />
class LongContent extends React.Component {
render() {
return (
<div>
<ScrollToTopOnMount />
<h1>Here is my long content page</h1>
<p>...</p>
</div>
);
}
}
通用解决方案
对于通用解决方案(以及哪些浏览器已开始在本机实现),我们谈论的是两件事:
1、向上滚动导航,这样就不会启动滚动到底部的新屏幕
2、恢复窗口的滚动位置和“后退”和“前进”单击上的溢出元素(但不单击“链接”单击!)
在某一时刻,我们希望提供一个通用的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组件时,它们可以从sessionStorage查找其位置。
最棘手的部分是定义一个"opt-out"的API,当你不想滚动窗口时进行管理。例如,如果您在页面内容中浮动了一些选项卡导航,则可能不想滚动到顶部(选项卡可能会滚动到视图之外!)。当我们得知Chrome现在可以为我们管理滚动位置,并意识到不同的应用程序将具有不同的滚动需求时,我们有点迷失了我们需要提供某些东西的信念,尤其是当人们只想滚动到顶部时( 您可以直接将其直接添加到您的应用中)。基于此,我们不再有足够的力气自己完成工作(就像您一样,我们的时间有限!)。 但是,我们很乐意为有志于实施通用解决方案的任何人提供帮助。 一个可靠的解决方案甚至可以存在于项目中。 如果您开始使用它,请与我们联系:)
设计原理
本指南的目的是说明使用React Router时要具有的思维模型。 我们称之为“动态路由”,它与您可能更熟悉的“静态路由”完全不同。
静态路由
如果您使用过Rails,Express,Ember,Angular等,则使用了静态路由。 在这些框架中,您需要在进行任何渲染之前将路由声明为应用初始化的一部分。 React Router pre-v4也是静态的(大部分是静态的)。让我们看一下在express中如何配置路由:
Express路由配置模式:
app.get("/", handleIndex);
app.get("/invoices", handleInvoices);
app.get("/invoices/:id", handleInvoice);
app.get("/invoices/:id/edit", handleInvoiceEdit);
app.listen();
请注意在app监听之前如何声明路由。 我们使用的客户端路由器相似。 在Angular中,您先声明routes,然后在渲染之前将其导入顶级的AppModule中:
// Angular的路由配置样式:
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 路由配置样式:
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,您需要忘记所有这些!
背后故事
坦率地说,我们对v2采取React Router的方向感到非常沮丧。 我们(Michael和Ryan)感到受到API的限制,认识到我们正在重新实现React的各个部分(生命周期等),而这与React为构建UI提供的思维模型不符。
我们走在一家酒店的走廊上,正在讨论如何解决这个问题。我们互相问:“如果我们使用我们在工作室里教的模式来建造路由器,那会是什么样子?”
仅仅在开发的几个小时内,我们就有了一个概念证明,我们知道这就是我们想要的路由的未来。我们最终得到的API不是React的“外部”API,而是一个由React的其余部分组成的API,或者自然地与之匹配。我们想你会喜欢的。
动态路由
当说动态路由时,是指在您的应用渲染时发生的路由,而不是在运行的应用之外的配置或约定中进行。 这意味着几乎所有内容都是React Router中的一个组件。 这是对该API的60秒回顾,以了解其工作原理:
首先,为您要定位的环境获取一个Router组件,并将其呈现在应用程序的顶部。
// react-native
import { NativeRouter } from "react-router-native";
// react-dom (我们将在这里使用什么)
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是路由器特定的东西,props对象以这三个关键对象{match,location, history}。 如果用户不在/dashboard上,则Route将渲染null。 差不多就够了。
嵌套路由
很多路由器都有“嵌套路由”的概念。如果您使用的是v4之前的React Router版本,那么您也会知道它是这么做的!当您从静态路由配置转移到动态渲染路由时,如何“嵌套路由”?如何嵌套div呢?
const App = () => (
<BrowserRouter>
{/* 这是一个 div */}
<div>
{/* 这是一个 Route */}
<Route path="/tacos" component={Tacos} />
</div>
</BrowserRouter>
);
// 当网址与`/ tacos`相匹配时,渲染此组件
const Tacos = ({ match }) => (
// 这是一个嵌套的div
<div>
{/* 这是一条嵌套路线match.url帮助我们建立相对路径 */}
<Route path={match.url + "/carnitas"} component={Carnitas} />
</div>
);
看到路由器没有“嵌套”API了吗?路由只是一个组件,就像div一样。要嵌套一个路由或div,你只需要...
让我们更加棘手。
响应式路由
考虑用户导航到/invoices。 您的应用程序适应不同的屏幕尺寸,它们的viewport狭窄,因此您只向他们显示发票清单和发票仪表板的链接。 他们可以从那里更深入地导航。
小屏幕
url: /invoices
+----------------------+
| |
| Dashboard |
| |
+----------------------+
| |
| Invoice 01 |
| |
+----------------------+
| |
| Invoice 02 |
| |
+----------------------+
| |
| Invoice 03 |
| |
+----------------------+
| |
| Invoice 04 |
| |
+----------------------+
在较大的屏幕上,我们想显示一个主从视图,其中导航在左侧,仪表板或特定发票在右侧。
大屏幕
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>
{/* 总是显示导航 */}
<InvoicesNav />
<Media query={PRETTY_SMALL}>
{screenIsSmall =>
screenIsSmall ? (
// 小屏幕没有重定向
<Switch>
<Route
exact
path="/invoices/dashboard"
component={Dashboard}
/>
<Route path="/invoices/:id" component={Invoice} />
</Switch>
) : (
// 大屏幕呢!
<Switch>
<Route
exact
path="/invoices/dashboard"
component={Dashboard}
/>
<Route path="/invoices/:id" component={Invoice} />
<Redirect from="/invoices" to="/invoices/dashboard" />
</Switch>
)
}
</Media>
</Layout>
);
当用户将手机从纵向旋转到横向时,此代码将自动将其重定向到仪表板。 有效routes会根据用户手中移动设备的动态性质而变化。
这只是一个例子。 我们可以讨论许多其他内容,但我们将总结以下建议:为了使您的直觉与React Router的直觉相符,请考虑组件而不是静态路由。 考虑一下如何使用React的声明式可组合性解决问题,因为几乎每个“ React Router问题”都可能是“ React问题”。
测试
React Router依靠React上下文来工作。 这会影响您如何测试在你的组件里使用我们的组件。
Context
如果您尝试对渲染或的组件之一进行单元测试,等等。您会收到一些有关上下文的错误和警告。 尽管您可能会想自己亲自设置路由器上下文,我们建议您将单元测试包装在路由器组件之一中:具有history属性的路由或,或的基本路由器(如果window.history在测试环境中可作为全局变量使用)。建议使用MemoryRouter或自定义历史记录,以便能够在两次测试之间重置路由器。
class Sidebar extends Component {
// ...
render() {
return (
<div>
<button onClick={this.toggleExpand}>expand</button>
<ul>
{users.map(user => (
<li>
<Link to={user.path}>{user.name}</Link>
</li>
))}
</ul>
</div>
);
}
}
// broken
test("it expands when the button is clicked", () => {
render(<Sidebar />);
click(theButton);
expect(theThingToBeOpen);
});
// fixed!
test("it expands when the button is clicked", () => {
render(
<MemoryRouter>
<Sidebar />
</MemoryRouter>
);
click(theButton);
expect(theThingToBeOpen);
});
从指定route开始
支持initialEntries和initialIndex props,因此您可以在特定位置启动应用程序(或应用程序的任何较小部分)。
test("current user is active in sidebar", () => {
render(
<MemoryRouter initialEntries={["/users/2"]}>
<Sidebar />
</MemoryRouter>
);
expectUserToBeActive(2);
});
导航
我们进行了很多测试,以检查route在位置更改时是否有效,因此您可能不需要测试这些东西。 但是,如果您需要在应用程序中测试导航,则可以这样进行:
app.js (a component file)
import React from "react";
import { Route, Link } from "react-router-dom";
// 我们的主题,即应用,但您可以测试任何子项
// 您的应用程序部分
const App = () => (
<div>
<Route
exact
path="/"
render={() => (
<div>
<h1>Welcome</h1>
</div>
)}
/>
<Route
path="/dashboard"
render={() => (
<div>
<h1>Dashboard</h1>
<Link to="/" id="click-me">
Home
</Link>
</div>
)}
/>
</div>
);
// 您还可以在此处使用"@testing-library/react"或"enzyme/mount"之类的渲染器
import { render, unmountComponentAtNode } from "react-dom";
import { act } from \'react-dom/test-utils\';
import { MemoryRouter } from "react-router-dom";
// app.test.js
it("navigates home when you click the logo", async => {
// 在真实测试中,渲染器如"@testing-library/react"
// 将负责设置DOM元素
const root = document.createElement(\'div\');
document.body.appendChild(root);
// Render app
render(
<MemoryRouter initialEntries={[\'/my/initial/route\']}>
<App />
<MemoryRouter>,
root
);
// 与页面互动
act(() => {
// 查找链接(可能使用文本内容)
const goHomeLink = document.querySelector(\'#nav-logo-home\');
// Click it
goHomeLink.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
// 检查显示的页面内容是否正确
expect(document.body.textContent).toBe(\'Home\');
});
检查测试中的位置
在测试中,您不必经常访问location或history对象,但是如果你这样做了(比如验证在url栏中设置了新的查询参数),你可以在测试中添加一个更新变量的路由:
// app.test.js
test("clicking filter links updates product query params", () => {
let history, location;
render(
<MemoryRouter initialEntries={["/my/initial/route"]}>
<App />
<Route
path="*"
render={({ history, location }) => {
history = history;
location = location;
return null;
}}
/>
</MemoryRouter>,
node
);
act(() => {
// example: click a <Link> to /products?id=1234
});
// assert about url
expect(location.pathname).toBe("/products");
const searchParams = new URLSearchParams(location.search);
expect(searchParams.has("id")).toBe(true);
expect(searchParams.get("id")).toEqual("1234");
});
备选方案:
1、如果您的测试环境具有浏览器全局变量window.location和window.history(这是通过JSDOM在Jest中的默认设置,但您无法重置测试之间的历史记录),则也可以使用BrowserRouter。
2、您可以将基本路由器与history包中的history props一起使用,而不是将自定义路由传递给MemoryRouter:
// app.test.js
import { createMemoryHistory } from "history";
import { Router } from "react-router";
test("redirects to login page", () => {
const history = createMemoryHistory();
render(
<Router history={history}>
<App signedInUser={null} />
</Router>,
node
);
expect(history.location.pathname).toBe("/login");
});
React测试包
请参阅官方文档中的示例:Testing React Router with React Testing Library
Redux集成
Redux是React生态系统的重要组成部分。 对于想要同时使用React Router和Redux的人,我们希望使其无缝集成。
阻止更新
通常,React Router和Redux可以很好地协同工作。不过有时候,应用程序可以包含一个组件,该组件在位置更改时(子routes或活动的导航links不会更新)不会更新。
在以下情况下会发生这种情况:
1、该组件通过connect()(Comp)连接到redux。
2、该组件不是“路由组件”,这意味着它的渲染方式不是这样:
问题在于Redux实现了shouldComponentUpdate,如果没有从路由器接收props,则没有任何迹象表明发生了任何变化。
这很容易姐姐,找到连接组件的位置,然后将组件使用withRouter包装在一起
深度集成
有些人想:
1、从store同步路由数据,并从store访问路由数据。
2、可以通过dispatch action操作导航
3、在Redux devtools中支持对路径更改进行时间行程调试。
所有这些都需要更深入的集成。
我们的建议是不要将routes完全保留在Redux store中。论证:
1、路由数据已经成为大多数关心它的组件的支持。 无论是来自store还是router,您组件的代码都基本相同。
2、在大多数情况下,您可以使用Link,NavLink和Redirect执行导航操作。有时您可能还需要以编程方式进行导航,有时您可能还需要以编程方式导航,在某个操作最初启动的异步任务之后。例如,您在用户提交登录表单时调度操作。然后,您的使用thunk,saga或其他异步处理程序会对凭据进行身份验证,如果成功,则需要以某种方式导航到新页面。此处的解决方案只是将history对象(提供给所有路由组件)包括在操作的payload,并且异步处理程序可以在适当的时候使用此对象进行导航。
3、路线更改对于时间行程调试不太重要。唯一明显的情况是调试router/store同步中的问题,如果根本不同步它们,则该问题将消失。
但是,如果您强烈希望与store同步route,您可能需要尝试Connected React Router,这是React Router v4和Redux的第三方绑定。
静态Routes
以前版本的React Router使用静态路由来配置应用程序的路由。这样可以在渲染之前检查和匹配路线。由于v4转移到动态组件而不是路由配置,因此一些以前的用例变得不那么明显和棘手。我们正在开发一个可与静态路由配置和React Router配合使用的软件包,以继续满足这些用例。 现在正在开发中,但我们希望您能尝试一下并提供帮助。
React Router Config
API
Hooks
React Router附带了一些钩子,可让您访问路由器的状态并从组件内部执行导航。
请注意:您必须使用React> = 16.8才能使用这些钩子中的任何一个!
- useHistory
- useLocation
- useParams
- useRouteMatch
useHistory
useHistory钩子使您可以访问可用于导航的history实例。
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钩子返回代表当前URL的location对象。您可以像useState一样考虑它,只要URL更改,它就会返回一个新位置。
这可能非常有用,例如 在您希望每次加载新页面时都使用Web分析工具触发新的"page view"事件的情况下,如以下示例所示:
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参数的key/value的对象。 使用它来访问当前的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钩子尝试以与相同的方式匹配当前URL。它主要用于在不实际渲染的情况下访问匹配数据。
不用useRouteMatch:
import { Route } from "react-router-dom";
function BlogPost() {
return (
<Route
path="/blog/:slug"
render={({ match }) => {
// 用match做你想做的一切...
return <div />;
}}
/>
);
}
使用useRouteMatch:
import { useRouteMatch } from "react-router-dom";
function BlogPost() {
let match = useRouteMatch("/blog/:slug");
// 用match做你想做的一切...
return <div />;
}
一个,它使用HTML5 history API (pushState、replaceState和popstate事件)来保持UI与URL同步。
<BrowserRouter
basename={optionalString}
forceRefresh={optionalBool}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App />
</BrowserRouter>
basename: string
所有location的基本URL。如果您的应用是通过服务器上的子目录提供的,则需要将其设置为子目录。格式正确的basename
应以斜杠开头,但不能以斜杠结尾。
getUserConfirmation: func
用于确认导航的功能。 默认使用window.confirm。
forceRefresh: bool
如果为true,则路由器将在页面导航中使用整页刷新。您可能希望使用它来模仿传统的服务器渲染应用程序在页面导航之间刷新整个页面的方式。
keyLength: number
location.key的长度。 默认为6。
children: node
要渲染的子元素。
注意:在React <16上,您必须使用单个子元素,因为render方法不能返回多个元素。 如果需要多个元素,则可以尝试将它们包装在额外的
中。 ============
使用URL的哈希部分(即window.location.hash)使UI与URL保持同步。
重要说明:Hash history不支持location.key或location.state。在以前的版本中,我们试图纠正这种行为,但是有些边缘情况我们无法解决。任何需要此行为的代码或插件都将无法使用。 由于此技术仅旨在支持旧版浏览器,我们建议您将服务器配置为与一起使用。
<HashRouter
basename={optionalString}
getUserConfirmation={optionalFunc}
hashType={optionalString}
>
<App />
</HashRouter>
basename: string
所有location的基本URL。 格式正确的basename应以斜杠开头,但不能以斜杠结尾。
<HashRouter basename="/calendar"/>
<Link to="/today"/> // 渲染出来的样子: <a href="#/calendar/today">
getUserConfirmation: func
用于confirm导航的功能。 默认使用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
的hash - "noslash" - 创建像
#
和#sunshine/lollipops
的hash - "hashbang" - 创建诸如
#!/
和#!/sunshine/lollipops
之类的"ajax crawlable"(Google弃用)hash
默认为 "/"
children: node
要渲染的单个子元素。
import React, { useEffect } from \'react\';
import ReactDOM from \'react-dom\';
import { HashRouter, Switch, Route, Link, withRouter } from \'react-router-dom\';
function INav() {
let homeRef;
let anchorRef = React.createRef();
console.log(\'before - anchorRef=>\', anchorRef);
useEffect(props => {
console.log(\'after - anchorRef=>\', anchorRef);
console.log(\'after- homeRef=>\', homeRef);
});
return (
<ul className={\'nav\'}>
<li>
<Link to={\'/home\'} replace innerRef={homeRef}>Home</Link>
</li>
<li>
<Link to={\'/rule\'} innerRef={anchorRef}>Rule</Link>
</li>
<li>
<Link to={\'/form\'} innerRef={node => {
// "node"指的是被挂载的DOM元素
// 组件被卸载时为null
console.log(\'node=>\', node);
}}>Form</Link>
</li>
<li>
<Link to={location => `/table?sort=name`}>Table</Link>
</li>
<li>
<Link to={location => {
console.log(\'Charts - location=>\', location);
return { ...location, pathname: \'/charts\' }
}}>Charts</Link>
</li>
<li>
<Link to={{
pathname: \'/example\',
search: \'?sort=name\',
hash: \'#the-hash\',
state: {
fromDashboard: true,
name: \'Jameswain\'
}
}}>Example</Link>
</li>
</ul>
)
}
function Home(props) {
console.log(\'Home:\', props);
return <h1>
Home
</h1>
}
function Form(props) {
console.log(\'Form:\', props);
return <h1>Form</h1>;
}
function Table(props) {
console.log(\'Table:\', props);
return <h1>Table</h1>
}
function Rule(props) {
console.log(\'rule:\', props);
return <h1>
Rule
</h1>
}
const Example = withRouter((props) => {
console.log(\'Example:\', props);
return <h1>Example</h1>
});
const Charts = withRouter((props) => {
console.log(\'Charts:\', props);
return <h1>Charts</h1>
});
function App() {
return (
<HashRouter hashType={\'noslash\'} basename={\'/calendar\'}>
<div className={\'app\'}>
<INav/>
<Switch>
<Route path={\'/home\'} exact>
<Home />
</Route>
<Route path={\'/rule\'} children={props => <Rule {...props} />} />
<Route path={\'/form\'} render={props => <Form {...props} />} />
<Route path={\'/table\'} component={props => <Table {...props} />} />
<Route path={\'/charts\'} children={<Charts />} />
<Route path={\'/example\'}>
<Example />
</Route>
</Switch>
</div>
</HashRouter>
);
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
======
提供围绕应用程序的声明式、可访问的导航,其实渲染出来的就是一个标签,对标签的封装。
<Link to="/about">About</Link>
to: string
链接位置的字符串表示形式,是通过将location的pathname,search和hash属性连接起来而创建的。
<Link to="/courses?sort=name" />
to: object
可以具有以下任何属性的对象:
- pathname: 表示要链接到的路径的字符串。
- search: query参数的字符串表示形式。
- hash: 网址中的hash值,例如#a-hash。
- state: 状态保留到该属性中,这个属性设置的内容会被传递到
location.state
中
<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
如果为true,则将单击链接替换为history记录堆栈中的当前条目,而不是添加一条新条目。
这样就没有回退功能了,因为它是把当前URL地址替换掉,不会产生历史记录。
<Link to="/courses" replace />
innerRef: function
从React Router 5.1开始,如果您使用的是React16,则不需要此props,因为我们会将ref转发到基础。允许访问组件的基础引用。
<Link
to="/"
innerRef={node => {
// “node”指的是被挂载的DOM元素
// 组件被卸载时为null
}}
/>
innerRef: RefObject
从React Router 5.1开始,如果您使用的是React16,则不需要此props,因为我们会将ref转发到基础。使用React.createRef获取组件的基础引用。
let anchorRef = React.createRef()
<Link to="/" innerRef={anchorRef} />
其他
您还可以传递想要在上显示的props,例如title,id,className等。
的特殊版本,当它与当前URL匹配时,它将为渲染的元素添加样式属性。
<NavLink to="/about">About</NavLink>
activeClassName: string
当元素处于active时给该元素设置的class,默认给定的class是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,则仅在locatiuon完全匹配时才应用active的class或style。
<NavLink exact to="/profile">
Profile
</NavLink>
strict: bool
如果为true,则在确定位置是否与当前URL匹配时,将会考虑位置路径名上的斜杠,它需要和配合使用。有关更多信息,请参见文档。
// 严格模式,无法匹配,URL必须要一模一样才能匹配上
<NavLink strict to="/events">
Events
</NavLink>
<Switch>
<Route path={\'/events/\'} strict children={<Events />} />
</Switch>
isActive: func
一种添加额外逻辑以确定链接是否处于active状态的功能。如果您要做的事情不仅仅是验证链接的路径名是否与当前URL的路径名匹配,则可以使用此选项。
<NavLink
to="/events/123"
isActive={(match, location) => {
if (!match) {
return false;
}
// 仅当事件id为奇数时元素才为active状态
const eventID = parseInt(match.params.eventID);
return !isNaN(eventID) && eventID % 2 === 1;
}}
>
Event 123
</NavLink>
location: object
isActive比较当前历史记录位置(通常是当前浏览器URL)。如果要与其他location进行比较,可以传递一个位置。
aria-current: string
在active链接上使用的aria-current属性的值。可用值为:
"page"
- 用于指示一组分页链接中的链接"step"
- 用于指示基于步骤的过程的步骤指示器中的链接"location"
- 用于指示视觉上突出显示的图像作为流程图的当前组成部分"date"
- 用于指示日历中的当前日期"time"
- 用于指示时间表中的当前时间"true"
- 用于指示NavLink是否处于活动状态
默认值为 "page"
基于WAI-ARIA 1.1规范
import React from \'react\';
import ReactDOM from \'react-dom\';
import { HashRouter, Switch, Route, NavLink } from \'react-router-dom\';
function Home() {
return <h1>Home</h1>
}
function About() {
return <h1>About</h1>
}
const Charts = () => <h1>Charts</h1>;
const Table = () => <h1>Table</h1>;
const FAQ = () => <h1>FAQ</h1>;
const Events = () => <h1>Events</h1>;
function App() {
return <div className={\'app\'}>
<HashRouter hashType={\'noslash\'}>
<ul>
<li>
<NavLink to={\'/home\'} className={\'home\'}>Home</NavLink>
</li>
<li>
<NavLink to={\'/about\'} className={\'about\'}>About</NavLink>
</li>
<li>
<NavLink to={\'/charts\'} className={\'charts\'} activeClassName={\'selected\'}>Charts</NavLink>
</li>
<li>
<NavLink to={\'/table\'} className={\'table\'} activeClassName={\'selected\'}>Table</NavLink>
</li>
<li>
<NavLink to={\'/faq\'} activeStyle={{ fontWeight: \'bold\', color: \'red\' }}>FAQ</NavLink>
</li>
<li>
<NavLink strict to="/events">Events</NavLink>
</li>
</ul>
<Switch>
<Route path={\'/home\'} children={<Home/>} />
<Route path={\'/about\'} children={<About/>} />
<Route path={\'/charts\'} children={<Charts/>} />
<Route path={\'/table\'} children={<Table/>} />
<Route path={\'/faq\'} children={<FAQ />} />
<Route path={\'/events/\'} strict children={<Events />} />
</Switch>
</HashRouter>
</div>
}
ReactDOM.render(<App />, document.querySelector(\'#root\'))
========
用于在离开页面之前提示用户。当您的应用程序进入应阻止用户导航的状态时(例如,表单已被半填满),请渲染。
<Prompt
when={formIsHalfFilledOut}
message="您确定要离开吗?"
/>
message: string
当用户尝试离开时提示用户的消息。
<Prompt message="Are you sure you want to leave?" />
message: func
将与用户尝试导航到的下一个位置和操作一起调用。返回一个字符串以向用户显示提示,或者返回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?" />
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Link, Prompt } from \'react-router-dom\';
function Home() {
return <h1>Home</h1>
}
function Table() {
return <h1>Table</h1>;
}
function Charts() {
return <h1>Charts</h1>
}
function About() {
return <h1>About</h1>
}
function App() {
return <BrowserRouter>
<Prompt message={location => {
if (location.pathname !== \'/home\') {
return `您确定要前往${location.pathname}吗?`
} else {
return true;
}
return true;
}} when={true} />
<ul>
<li>
<Link to={\'/home\'}>Home</Link>
</li>
<li>
<Link to={\'/table\'}>Table</Link>
</li>
<li>
<Link to={\'/charts\'}>Charts</Link>
</li>
<li>
<Link to={\'/about\'}>About</Link>
</li>
</ul>
<Switch>
<Route path={\'/home\'} children={props => <Home {...props} />} />
<Route path={\'/table\'} render={props => <Table {...props} />} />
<Route path={\'/charts\'} children={props => <Charts {...props} />} />
<Route path={\'/about\'} render={props => <About {...props} />} />
</Switch>
</BrowserRouter>;
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
==========
渲染将导航到新位置。新位置将覆盖历史记录堆栈中的当前位置,就像服务器端重定向(HTTP 3xx)一样。
<Route exact path="/">
{loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>
to: string
重定向到的URL。path-to-regexp@^1.7.0可以理解的任何有效URL路径。to中使用的所有URL参数必须由from覆盖。
<Redirect to="/somewhere/else" />
to: object
重定向到的位置。路径名可以是path-to-regexp@^1.7.0可以理解的任何有效URL路径。
<Redirect
to={{
pathname: "/login",
search: "?utm=your+face",
state: { referrer: currentLocation }
}} />
可以通过重定向到组件中的this.props.location.state访问状态对象。然后,可以通过路径名"/login"指向的Login组件中的this.props.location.state.referrer访问此新的引用关键字(不是特殊名称)。
push: bool
<Redirect push to="/somewhere/else" />
设置为true时,重定向会将新条目推入历史记录,而不是替换当前条目。
from: string
要重定向的路径名。 path-to-regexp@^1.7.0可以理解的任何有效URL路径。所有匹配的URL参数都提供给模式中的to。必须包含用于to中的所有参数。to不使用的其他参数将被忽略。
<Switch>
<Redirect from=\'/old-path\' to=\'/new-path\' />
<Route path=\'/new-path\'>
<Place />
</Route>
</Switch>
// 使用匹配的参数重定向
<Switch>
<Redirect from=\'/users/:id\' to=\'/users/profile/:id\'/>
<Route path=\'/users/profile/:id\'>
<Profile />
</Route>
</Switch>
示例:
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Redirect, Link, useParams } from \'react-router-dom\';
function App() {
return(
<BrowserRouter>
<ul>
<li>
<Link to={\'/home\'}>Home</Link>
</li>
<li>
<Link to={\'/charts/123123\'}>Charts</Link>
</li>
<li>
<Link to={\'/profile/111\'}>Profile</Link>
</li>
</ul>
<Switch>
<Route path={\'/home\'} render={props => <Home {...props} />} />
<Route path={\'/profile/:id\'} render={props => <Profile {...props} />} />
<Redirect from={\'/charts/:id\'} to={\'/profile/:id\'} />
</Switch>
</BrowserRouter>
)
}
function Home() {
return <h1>Home</h1>
}
function Profile() {
const params = useParams();
console.log(\'params=>\', params);
return <>
<h1>Profile</h1>
</>
}
ReactDOM.render(<App />, document.querySelector(\'#root\'));
exact: bool
完全匹配;等同于Route.exact。
注意:只有在内渲染时,才能与from结合使用,以完全匹配位置。有关更多详细信息,请参见。
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Link, Redirect } from \'react-router-dom\';
const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;
const App = () => <BrowserRouter>
<ul>
<li>
<Link to={\'/home\'}>Home</Link>
</li>
<li>
<Link to={\'/about\'}>About</Link>
</li>
</ul>
<Switch>
<Route path={\'/home\'} render={props => <Home {...props} />} />
<Route path={\'/about\'} children={props => <About {...props} />} />
{/*这个一定要放到Route后面,等Route渲染完了,才可以重定向*/}
<Redirect exact from={\'/\'} to={\'/home\'} />
</Switch>
</BrowserRouter>;
ReactDOM.render(<App />, document.querySelector(\'#root\'));
strict: bool
严格匹配;等同于Route.strict。
注意:只有在内部渲染时,此选项只有与from一起使用才能以严格匹配位置。有关更多详细信息,请参见。
import React from \'react\';
import ReactDOM from \'react-dom\';
import { BrowserRouter, Switch, Route, Link, Redirect } from \'react-router-dom\';
const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;
const App = () => <BrowserRouter>
<ul>
<li>
<Link to={\'/home\'}>Home</Link>
</li>
<li>
<Link to={\'/about\'}>About</Link>
</li>
<li>
<Link to={\'/one\'}>One</Link>
</li>
</ul>
<Switch>
<Route path={\'/home\'} render={props => <Home {...props} />} />
<Route path={\'/about\'} children={props => <About {...props} />} />
{/*这个一定要放到Route后面,等Route渲染完了,才可以重定向*/}
<Redirect strict from="/one/" to="/home" />
</Switch>
</BrowserRouter>;
ReactDOM.render(<App />, document.querySelector(\'#root\'));
sensitive: bool
区分大小写匹配;等同于Route.sensitive。
<Route sensitive path="/one">
<About />
</Route>
path
location.pathname
sensitive
是否匹配
/one
/one
true
yes
/One
/one
true
no
/One
/one
false
yes
Router组件可能是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
);
如果应用程序的location是/,则UI层次结构将类似于:
<div>
<Home />
<!-- react-empty: 2 -->
</div>
如果应用程序的location是/news,则UI层次结构将是:
<div>
<!-- react-empty: 1 -->
<NewsFeed />
</div>
"react-empty"注释只是React空渲染的实现细节。但是出于我们的目的,这是有益的。从技术上讲,即使始终为空,也总是对其进行"渲染"。当的路径与当前URL匹配时,它将渲染其子级(您的组件)。
Route render methods
使用渲染某些内容的方法建议使用子元素,如上所示。 但是,还有一些其他方法可用于使用渲染内容。 提供这些主要是为了支持在引入钩子之前使用早期版本的路由器构建的应用程序。
<Route component>
<Route render>
<Route children>
function
您应该在给定的上仅使用这些props。 请参阅下面的说明以了解它们之间的区别。
Route props
所有这三种渲染方法将通过相同的三个路由props
- match
- location
- history
component
一个仅在location匹配时才渲染的React组件。 它将与route props一起渲染。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
// 用户可以使用所有route props(match, location and history)
function User(props) {
return <h1>Hello {props.match.params.username}!</h1>;
}
ReactDOM.render(
<Router>
<Route path="/user/:username" component={User} />
</Router>,
node
);
当您使用组件(而不是下面的渲染器或子组件)时,路由器会使用React.createElement从给定的组件中创建一个新的React元素。这意味着,如果您向组件prop提供内联函数,则将在每个渲染中创建一个新组件。这意味着,如果您向组件prop提供内联函数,则将在每个渲染中创建一个新组件。这将导致现有组件的卸载和新组件的安装,而不仅仅是更新现有组件。使用内联函数进行内联渲染时,请使用render或children属性(如下)。
render: func
这样可以方便地进行内联渲染和包装,而无需进行上述不必要的重新安装。
无需使用组件prop为您创建新的React元素,而是可以传
以上是关于react-router-dom@5.x官方文档翻译转载的主要内容,如果未能解决你的问题,请参考以下文章
Android官方文档之Creating a Content Provider