react-router-dom API 详解,入门(一)

3,934 阅读12分钟

API

Hooks(钩子)

useHistory

useHistory钩子,可以进行路由导航。

// useHistory
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, Route, Switch, useHistory, withRouter } from 'react-router-dom';

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  const history = useHistory();

  const handleClick = () => {
    console.log(useHistory);
    history.push('/');
  };
  return (
    <>
      <div>About</div>
      <button type="button" onClick={handleClick}>
        Go home
      </button>
    </>
  );
};

const TestHomeButton = () => {
  const history = useHistory();

  const errClick = () => {
    console.log(useHistory);
    history.push('/');
  };
  return (
    <>
      <BrowserRouter>
        <button type="button" onClick={errClick}>
          Go home(错误方式)
        </button>
        <h1>App</h1>
        <ul>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/">home</Link>
          </li>
        </ul>
        <Switch>
          <Route exact={true} path="/" component={Home} />
          <Route exact={true} path="/about" component={About} />
        </Switch>
      </BrowserRouter>
    </>
  );
};

ReactDOM.render(<TestHomeButton />, document.body);
    

注意useHistory使用的条件,使用不当会报错 ' Cannot read property 'push' of undefined',原因: 您正试图在Router之外使用history钩子。在对应组件中编写函数。

useLocation

useLocation钩子返回location表示当前URL对象。您可以将其视为一个useState,每当URL更改时,它都会返回一个URL对象. 这可能非常有用,例如在您希望在加载新页面时监视location变化做点事情,如下例所示:

// useLocation
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, Route, Switch, useLocation } from 'react-router-dom';

const Home = () => {
  let location = useLocation();
  React.useEffect(() => {
    console.log(location);
    // alert('做自己喜欢的事情');
  }, [location]);
  return <div>home</div>;
};

const App = () => {
  return (
    <>
      <BrowserRouter>
        <h1>App</h1>
        <ul>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/">home</Link>
          </li>
        </ul>
        <Switch>
          <Route exact={true} path="/" component={Home} />
          <Route exact={true} path="/about" render={() => <div>about</div>} />
        </Switch>
      </BrowserRouter>
    </>
  );
};

ReactDOM.render(<App />, document.body);

location:

{
  hash: '',
  key: 'y01zme',
  pathname: '/',
  search: '',
  state: undefined,
}

注意需要在Router之内使用,要不然报错。

useParams

useParams返回 URL 参数的键/值对对象。使用它来获取<Route>参数.

// useParams
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, Route, Switch, useParams } from 'react-router-dom';

const About = () => {
  let params = useParams();
  return <div>useParams: {JSON.stringify(params)}</div>;
};

const App = () => {
  return (
    <>
      <BrowserRouter>
        <h1>App</h1>
        <ul>
          <li>
            <Link to="/about/xxxx">About</Link>
          </li>
          <li>
            <Link to="/">home</Link>
          </li>
        </ul>
        <Switch>
          <Route exact={true} path="/" render={() => <div>home</div>} />
          <Route exact={true} path="/about/:slug" component={About} />
        </Switch>
      </BrowserRouter>
    </>
  );
};

ReactDOM.render(<App />, document.body);

对象key 取决于path参数/:slug的slug

useRouteMatch

useRouteMatch挂钩尝试以与<Route>相同的方式匹配当前URL。在无需实际呈现<Route>的情况下访问匹配数据最有用.\

不带参数时候,返回<Route>match对象。

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, Route, Switch, useRouteMatch } from 'react-router-dom';

const About = () => {
  let match = useRouteMatch();
  return <div>useRouteMatch: {JSON.stringify(match)}</div>;
};

const App = () => {
  return (
    <>
      <BrowserRouter>
        <h1>App</h1>
        <ul>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/">home</Link>
          </li>
        </ul>
        <Switch>
          <Route exact={true} path="/" render={() => <div>home</div>} />
          <Route exact={true} path="/about" component={About} />
        </Switch>
      </BrowserRouter>
    </>
  );
};

ReactDOM.render(<App />, document.body);

match:

{
  "path":"/about",
  "url":"/about",
  "isExact":true, // 是否匹配
  "params":{}
}

接受参数时候,参数与match的props参数相同,它可以是字符串的路径名,也可以是带有组件的route对象

const match = useRouteMatch({
  path: "/BLOG/:slug/",
  strict: true,
  sensitive: true
});

BrowserRouter

使用HTML5historyAPI(pushState、replaceState和popstate事件)保持UI与URL同步的。

basename

路由前缀,格式正确的basename应该有一个前导斜杠,但没有尾随斜杠。

<BrowserRouter basename="/calendar">
    <Link to="/today"/> // renders <a href="/calendar/today">
    <Link to="/tomorrow"/> // renders <a href="/calendar/tomorrow">
    ...
</BrowserRouter>

getUserConfirmation

用于确认导航的功能。默认使用window.confirm

<BrowserRouter
  getUserConfirmation={(message, callback) => {
    // 这是默认行为
    const allowTransition = window.confirm(message);
    callback(allowTransition);
  }}
/>

hashType

用于 window.location.hash的编码类型。可用值为:

  • "slash" - Creates hashes like #/ and #/sunshine/lollipops
  • "noslash" - Creates hashes like # and #sunshine/lollipops
  • "hashbang" - Creates “ajax crawlable” (deprecated by Google) hashes like #!/ and #!/sunshine/lollipops

默认 slash

children

要渲染的单个子元素。

link

在应用程序周围提供声明性的、可访问的导航。

to: string

链接位置的字符串表示形式,通过url、search和hash属性渲染对应router。

<Link to="/about">About</Link>
<Link to="/courses?sort=name" />

to: string

可以具有以下任何属性的对象:

  • pathname: 表示要链接到的路径的字符串。
  • search: 查询参数的字符串表示形式。
  • hash: 查询参数的字符串表示形式。放在URL中的哈希,例如“A-hash”。
  • state: 要传输状态数据。
<Link
  to={{
    pathname: "/courses",
    search: "?sort=name",
    hash: "#the-hash",
    state: { fromDashboard: true }
  }}
/>

to: function

接收“location”的状态。作为参数传递给该函数,该函数应将返回to的对象或字符串路径。

<Link to={location => ({ ...location, pathname: "/courses" })} />
<Link to={location => `${location.pathname}?sort=name`} />

replace: boolean

如果为true,单击链接将替换历史堆栈中的当前条目,而不是添加新条目。

<Link to="/courses" replace />

innerRef: function

从React路由器5.1开始,如果您使用的是React 16,则不需要此api,因为我们将ref转发到基础a。改用普通的ref。

<Link
  to="/"
  innerRef={node => {
    // `node`指挂载的DOM元素
    // or null when unmounted
  }}
/>

innerRef: RefObject

如果您使用的是React 16,则不需要此api 使用React.createRef获取组件的底层ref;


let anchorRef = React.createRef()

<Link to="/" innerRef={anchorRef} />

在React 16 以上, 中直接使用ref


let anchorRef = React.createRef()

<Link to="/" ref={anchorRef} />

component: React.Component

如果您想使用自己的导航组件,只需通过组件api传递它即可。

const FancyLink = React.forwardRef((props, ref) => (
  <a ref={ref} {...props}>💅 {props.children}</a>
))

<Link to="/" component={FancyLink} />

others

您还可以传递在上使用的属性,如标题、id、类名等。

NavLink

<Link>的一个特殊版本,当呈现元素与当前URL匹配时,它将向呈现元素添加样式属性。

<NavLink to="/about">About</NavLink>

activeClassName: string

当元素处于活动状态时提供该元素的类。默认的给定元素是激活的。这将与className prop连接。

<NavLink to="/faq" activeClassName="selected">
  FAQs
</NavLink>

activeStyle: object

当元素处于活动状态时,应用于该元素的样式。

<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: "bold",
    color: "red"
  }}
>
  FAQs
</NavLink>

exact: bool

如果为true,则仅当完全匹配时才会应用组件。

<NavLink exact to="/profile">
  Profile
</NavLink>

strict: bool

如果为true,则仅当位置完全匹配时才会应用活动类/样式。如果为true,则在确定位置是否匹配当前URL时,将考虑位置路径名上的尾随斜杠。有关更多信息,请参阅文档。

<NavLink strict to="/events/">
  Events
</NavLink>

isActive: func

添加额外逻辑以确定链路是否处于活动状态的函数。如果您想做的不仅仅是验证链接的路径名是否与当前URL的路径名匹配,那么应该使用此选项。
只有isActive返回ture时候,activeStyle才生效。

<NavLink
  to="/blog/123"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red',
  }}
  isActive={(match, location) => {
    if (!match) {
      return false;
    }
    console.log(match, location);
    // 如果事件ID为奇数,则只考虑活动的事件。
    const ID = Math.floor(Math.random() * 100);
    return !isNaN(ID) && ID % 2 === 1;
  }}
>
  Event 123
</NavLink>

location: object

isActive比较当前历史位置(通常是当前浏览器URL)。要与其他位置进行比较,可以传递一个位置。

aria-current: string

活动链接上使用的当前属性的值。可用值包括:

  • "page" - used to indicate a link within a set of pagination links
  • "step" - used to indicate a link within a step indicator for a step-based process
  • "location" - used to indicate the image that is visually highlighted as the current component of a flow chart
  • "date" - used to indicate the current date within a calendar
  • "time" - used to indicate the current time within a timetable
  • "true" - used to indicate if the NavLink is active
  • "false" - used to prevent assistive technologies from reacting to a current link (a use case would be to prevent multiple aria-current tags on a single page)

Defaults to "page".

<MemoryRouter>

....暂不研究

<Redirect>

重定向,将导航到新位置。新位置将覆盖历史堆栈中的当前位置。

<Route exact path="/">
  {loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>

to: string

<Redirect to="/somewhere/else" />

to: object

<Redirect
  to={{
    pathname: "/login",
    search: "?utm=your+face",
    state: { referrer: currentLocation }
  }}
/>

push: bool

如果为true,重定向将在历史记录上推送一个新条目,而不是替换当前条目

<Redirect push to="/somewhere/else" />

from: string

from: 如果路径是/xx to: 跳转到/xxx
如:
<Redirect from="/old-path" to="/new-path" />
则:路径/old-path 重定向 /new-path

<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>

exact: bool

精确匹配

<Switch>
  <Redirect exact from="/" to="/home" />
  <Route path="/home">
    <Home />
  </Route>
  <Route path="/about">
    <About />
  </Route>
</Switch>

注意:当呈现<Switch>内部的<Redirect>时,这只能与from一起使用,以精确匹配位置。有关更多详细信息,详情reactrouter.com/web/api/Swi…

Route

路由组件可能是React路由器中最重要的组件,它可以帮助您更好地理解和学习如何使用。它最基本的职责是在其路径与当前URL匹配时呈现一些UI。

Route render methods

使用渲染推荐方法是使用childen,但是,您可以使用一些其他方法来使用渲染某些内容。

  • <Route component>
  • <Route render>
  • <Route children>  在给定的上,您应该只使用其中一种渲染方法。

Route props

所有三种渲染方法都将传递相同的三个路由参数

  • match
  • location
  • history

match

match对象包含有关如何匹配URL的信息。匹配对象包含以下属性:

  • params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path(从对应于路径动态段的URL解析的键/值对)
  • isExact - (boolean) true if the entire URL was matched (no trailing characters)(是否匹配当前url)
  • path - (string) The path pattern used to match. Useful for building nested <Route>(用于匹配路径。)
  • url - (string) The matched portion of the URL. Useful for building nested <Link>

You’ll have access to match objects in various places:
在不同的位置获取对象:

location

当前路由信息。看起来是这样的:

{
  key: 'ac3df4', // 不是历史!
  pathname: '/somewhere',
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

The router will provide you with a location object in a few places:
路由在以下位置提供对象:

// 通常你所需要的
<Link to="/somewhere"/>

// 但是你可以用一个准确对象来代替
const location = {
  pathname: '/somewhere',
  state: { fromDashboard: true }
}

<Link to={location}/>
<Redirect to={location}/>
history.push(location)
history.replace(location)

history

React Router提供了 BrowserRouter 和 HashRouter, 用于在各种环境下 JavaScript 管理会话历史。

  • “BrowserRouter” - 特定于 DOM 的实现,在支持 HTML5 历史 API 的 Web 浏览器中很有用

  • “HashRouter” - 旧版 Web 浏览器的特定于 DOM 的实现 history 对象通常具有以下属性和方法:

  • length - (number) 历史堆栈中的条目数

  • action- (string) 当前动作 ( PUSHREPLACE, or POP)

  • location- (对象)当前位置。可能具有以下属性:

    • pathname - (string) URL 的路径
    • search - (string) URL 查询字符串
    • hash - (string) URL 哈希片段
    • state-(对象)特定于位置的状态,例如push(path, state)当此位置被推送到堆栈时提供。仅在浏览器和内存历史记录中可用。
  • push(path, [state]) -(功能)将新条目推入历史堆栈

  • replace(path, [state]) - (function) 替换历史堆栈中的当前条目

  • go(n)- (function) 按n条目移动历史堆栈中的指针

  • goBack() - (功能)相当于 go(-1)

  • goForward() - (功能)相当于 go(1)

  • block(prompt)-(功能)阻止导航(请参阅历史文档

component

仅在位置匹配时呈现的 React 组件。它将使用[route props]进行渲染。

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";

const User = (props) => {
  return <h1>Hello {props.match.params.username}!</h1>;
}

ReactDOM.render(
  <Router>
    <Route path="/user/:username" component={User} />
  </Router>,
  node
);

当您使用component(而不是renderchildren)时,路由用于从给定的组件React.createElement创建一个新的React 元素。这意味着如果您为componentprop提供内联函数,您将在每次渲染时创建一个新组件。这会导致卸载现有组件并安装新组件,而不仅仅是更新现有组件。使用内联函数进行内联渲染时,请使用renderchildren道具(如下)。

render: func

render 属性能使你便捷的渲染内联组件或是嵌套组件,你可以给这个属性传入一个函数,当路由的路径匹配时调用,而不是使用 component 创建一个新的 React 元素。同时,render属性也会接受所有由route传入的所有参数。

//内联方式
    <Route path="path" render={() => <div>这是内联组件写法</div>} />
    //嵌套组合方式
    <Route path="path" render={ props => (
        <ParentComp>
            <Comp {...props} />
        </ParentComp>
    ) />

警告:  <Route component>优先,<Route render>所以不要在同一个<Route>.

children: func

children 属性是这三个属性中比较特殊的一个,它的值为一个函数,当 Route 有 children 属性时,不管当前的路径是否与Route匹配,该函数都会执行,同时,children属性也会接受所有由route传入的所有参数。

有时候不论 path 是否匹配位置,你都想渲染一些内容。在这种情况下,你可以使用 children 属性。除了不论是否匹配它都会被调用以外,它的工作原理与 render 完全一样。
children 渲染方式接收所有与 component和 render 方式相同的 route props,除非路由与 URL 不匹配,不匹配时 match 为 null。这允许你可以根据路由是否匹配动态地调整用户界面,如果路由匹配,添加一个激活类。

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';

function ListItemLink(props: any) {
  const { to, ...rest } = props;
  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>,
  document.body
);

警告:  <Route children>优先于两者<Route component><Route render>因此不要在同一个<Route>.

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, Route, Switch } from 'react-router-dom';

const About = () => {
  return <div>component</div>;
};

const Home = () => {
  return <div>Home</div>;
};

const App = () => {
  let anchorRef = React.createRef();
  React.useEffect(() => {
    console.log(anchorRef);
  }, [anchorRef]);
  return (
    <>
      <BrowserRouter>
        <h1>App</h1>
        <ul>
          <li>
            <Link to="/about" ref={anchorRef as any}>
              About
            </Link>
          </li>
          <li>
            <Link to="/">home</Link>
          </li>
        </ul>
        <Switch>
          {/* 渲染children */}
          <Route exact={true} path="/about" render={() => <div>'render'</div>} component={About} children={() => <div>'children'</div>} />
          {/* 渲染component */}
          <Route exact={true} path="/" render={() => <div>'renderHome'</div>} component={Home} />
        </Switch>
      </BrowserRouter>
    </>
  );
};
ReactDOM.render(<App />, document.body);

可以得出:

children > component > children

path: string | string[]

能够解析任何有效URL路径或路径数组。

<Route path="/users/:id">
  <User />
</Route>
<Route path={["/users/:id", "/profile/:id"]}>
  <User />
</Route>

没有路径的路由始终匹配。

exact: bool

true, 仅当路径与location.pathname 完全匹配时才匹配。

<Route exact path="/one">
  <About />
</Route>
路径位置.路径名准确的匹配?
/one/one/twotrue没有
/one/one/twofalse是的

strict: bool

当 为true,带有path尾部斜杠的, a只会匹配location.pathname带有尾部斜杠 a。当location.pathname为/one/时候:

<Route strict path="/one/">
  <About />
</Route>
路径位置.路径名匹配?
/one//one没有
/one//one/是的
/one//one/two是的

警告:  strict可用于强制 alocation.pathname没有尾部斜杠,但为了做到这一点strictexact必须是true.

<Route exact strict path="/one">
  <About />
</Route>
路径位置.路径名匹配?
/one/one是的
/one/one/没有
/one/one/two没有

location: object

一个<Route>元素尝试其匹配path到当前的历史位置(通常是当前浏览器URL)。但是,也可以传递location带有不同的 apathname进行匹配。

当您需要将 a<Route>与当前历史位置以外的位置匹配时,这很有用,如动画过渡示例所示。

sensitive: bool

如果true,如果路径是将匹配区分大小写

<Route sensitive path="/one">
  <About />
</Route>
路径位置.路径名敏感匹配?
/one/onetrue是的
/One/onetrue没有
/One/onefalse是的

Router

所有路由组件的通用低级接口。通常,应用程序将改用其中一个高级路由:

  • <BrowserRouter>
  • <HashRouter>
  • <MemoryRouter>
  • <NativeRouter>
  • <StaticRouter>

注意 低级接口,指基本的<Router>
使用低级的最常见用例<Router>是将自定义历史记录与 Redux 或 Mobx 等状态管理库同步。请注意,这不需要与 React Router 一起使用状态管理库,它仅用于深度集成。

import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router';
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
console.log(history);

const App = () => {
  return <div>app</div>;
};

ReactDOM.render(
  <Router history={history}>
    <App />
  </Router>,
  document.body
);

history: object

用于导航的历史对象。

import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";

const customHistory = createBrowserHistory();
console.log(history);

ReactDOM.render(<Router history={customHistory} />, node);

对象信息:

image.png

children: node

要渲染的子元素。

StaticRouter

请移步官网 reactrouter.com/web/api/Sta…

Switch

渲染第一个匹配的[<Route>]或[<Redirect>]。

这与仅使用一堆<Route> 有何不同?

<Switch>它的独特之处在于它专门呈现一条路线。相比之下,每个<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>进行渲染。如果我们在,/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>
    {/* 匹配404 */}
    <Route>
      <NoMatch />
    </Route>
  </Switch>
);

现在,如果我们在/about<Switch>将开始寻找匹配的<Route><Route path="/about"/>将匹配<Switch>并将停止寻找匹配和渲染<About>。同样,如果我们在/michaelthen<User>将渲染。

这对于动画过渡也很有用,因为匹配<Route>的渲染位置与前一个相同。

let routes = (
  <Fade>
    <Switch>
      {/* 这里永远只会渲染一个Route */}
      <Route />
      <Route />
    </Switch>
  </Fade>
);

let routes = (
  <Fade>
    {/* 这里总有两个孩子,
    不过,可能会在进行转换时呈现null
    做起来有点麻烦 */}
    <Route />
    <Route />
  </Fade>
);

参考文献

英文官网