React Router 中文文档(v5 )

44,311 阅读18分钟

引言

自从 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中的组件主要分为三类:

  1. 路由器,例如 BrowserRouter 和 HashRouter
  2. 路由匹配器: 例如Route和Switch
  3. 导航:例如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>
    );
  }
}

通用解决方案

对于通用解决方案(以及哪些浏览器已原生支持),我们谈论的是两件事:

  1. 向上滚动导航,这样就不会启动滚动到底部的新屏幕
  2. 恢复窗口的滚动位置和在“后退”和“前进”点击上溢出的元素(不是 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} />
pathlocation.pathnameexactmatches?
/one/one/twotrueno
/one/one/twofalseyes

strict:bool

如果为 true,则具有尾部斜杠的 path 仅与具有尾部斜杠的 location.pathname 匹配。当 location.pathname 中有附加的 URL 片段时,strict 就没有效果了。

<Route strict path="/one/">
  <About />
</Route>
pathlocation.pathnamematches?
/one//oneno
/one//one/yes
/one//one/two/yes

警告:strict可以用来强制location.pathname没有结尾的斜杠,但是要做到这一点,strict 和 exact 都必须为true。

<Route exact strict path="/one">
  <About />
</Route>
pathlocation.pathnamematches?
/one/oneyes
/one/one/no
/one/one/twono

sensitive: bool

如果为 true,进行匹配时将区分大小写。

<Route sensitive path="/one" component={OneComponent} />
pathlocation.pathnamesensitivematches?
/one/onetrueyes
/One/onetrueno
/One/onefalseyes

Router

Router 是所有路由器组件的通用底层接口。通常,应用程序只会从以下高阶Router中选择一个作为代替:

使用低阶 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 会将更新后的 matchlocationhistory 传递给它。

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} />
    )
  }
}