React 路由

React 路由

路由器

React-Router 支持我们使用 HashRouter 和 BrowserRouter 两种路由规则,react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现应用的 ui 和 url 同步

BrowserRouter 创建的 url 格式 http://xxx.com/path

HashRouter 创建的 url 格式 http://xxx.com/#/path

BrowserRouter

他是由 HTML5 提供的 history api 来保持 ui 和 url 同步的

1
2
3
4
5
6
<BrowserRouter
basename={string}
forceRefresh={bool}
getUserConfirmation={func}
keyLength={number}
/>

其中的参数如下:

bansename 所有的路由的基准 url,basename 的正确格式是前面有一个斜杠,但是尾部不能有斜杠

1
2
3
<BrowserRouter basename="/calendar">
<Link to="/today" />
</BrowserRouter>

等同于

1
<a href="/calendar/today" />
  • forceRefresh 如果为 true,在导航过程中页面将会刷新一下,一般情况下只有在不支持 html5 history api 的浏览器中使用此功能
  • getUserConfirmation 用于确认导航的函数,默认使用 window.confirm。例如当从/a 导航到/b 的时候,会默认使用 confirm 函数弹出一个提示,用户点击确定后才进行导航,否则不做任何处理。
1
2
3
4
5
6
// 这是默认的确认函数
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message);
callback(allowTransition);
};
<BrowserRouter getUserConfirmation={getConfirmation} />;
  • keylength 用来设置 location.key 的长度

HashRouter

使用 url 的 hash 部分(window.loaction.hash)来保持 ui 和 url 的同步。由此可以看出,HashRouter 是通过 url 的 hash 属性来控制路由跳转的

1
<HashRouter basename={string} getUserConfirmation={func} hashType={string} />

其中的参数如下:

  • basename,getuserconfirmation 和 BrowserRouter 功能一样
  • hashType.window.loaction.hash 使用的 hash 诶西,有如下几种
    • slash - 后面跟一个斜杠,例如#/和#/sunshine/fuck
    • noslash - 后面没有斜杠,例如#和#sunshine/fuck
    • hashbang - 谷歌风格的 ajax crawlable ,例如#! 和#!/sunshine/fuck

Route

react-router 的工作方式是在组件树的顶层放一个 Router 组件,然后在组件树中散落着很多 Route 组件,顶层 Router 组件负责分析监听 url 的变化而 Route 组件可以直接读取这些信息。Router 与 Route 配合,Router 是“提供者”,Route 是“消费者”

Route 的基本使用

Route 是 React Route 用于配制路由信息的组件,也是 React Router 中使用频率最高的组件。每当一个组件需要根据 url 决定是否渲染时,就需要创建一个 Route

1
<Route exact={bool} path={string} component={Component} />

其中的属性如下:

  • exact:当 url 完全匹配时,值为 true,否则为 false,它控制匹配 / 路径时是否向下继续匹配
  • path:构建嵌套路由时会使用到,每个 Route 都需要定一个 path 属性
  • component:表示路径对应显示的组件

url 匹配到 Route 时,Route 会创建一个 match 对象作为 props 中的一个属性传递给被渲染的组件。这个对象包含以下四个属性

  • params:Route 的 path 可以包含参数,params 就是用于从匹配到的 url 中解析出 path 中的参数
  • isExact:同 Route 的 exact
  • path:同 Route 的 path
  • url:url 的匹配方式

Route 渲染组件的方式

  1. component 属性

    component 属性的值是一个组件,当 URL 和 Route 匹配时,component 属性定义的组件就会被渲染

1
<Route path='/foo' component={Foo} >

当 url 为/foo 的时候 Foo 组件被渲染

  1. render(多用于权限验证)

    render 的值是一个函数,他返回一个 React 元素,这种方式方便的为待渲染的组件传递额外的属性

1
2
3
4
5
6
<Route
path="/foo"
render={(props) => {
<Foo {...props} data={extraProps} />;
}}
></Route>

Foo 组件接收到了额外的 data 属性

采用 render 方式渲染时,组件是否渲染不仅要看路径是否匹配,还要由 render 属性所接受的函数来共同决定。注意,此时 render 函数会接受一个参数 props,即当前 Route 组件的 props 对象。

  1. children(多用于菜单)

    children 的值也是一个函数,函数返回要渲染的 React 元素。与前两种方式的不同之处是,无论是否匹配成功,children 返回的组件都会被渲染。但是当匹配不成功的时候,match 属性为 null

1
2
3
4
5
6
7
8
<Route
path="/foo"
render={(props) => {
<div className={props.match ? "active" : ""}>
<Foo {...props} data={extraProps} />
</div>;
}}
></Route>

如果 Route 匹配当前 URL,待渲染的元素的根节点 div 的 class 将设置成 active。

Switch

switch 通常用来包裹 Route,用来渲染路径匹配的第一个<Route><Redirect>,他里面不能放其他元素

例如不加<Switch>

1
2
3
4
import { Route } from 'react-router-dom'

<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>

Route 组件的 path 属性用于匹配路径,因为我们需要匹配/到 Home,匹配/login 到 Login,所以需要两个 Route,但是,我们不能这么写。这么写的话,当 url 的 path 为/login 的时候,会同时匹配到/和/login,因此页面会显示 Home 和 Login 两个组件,这个时候就需要 switch 来做到只展示一个匹配组件。

1
2
3
4
5
6
import { Switch, Route } from "react-router-dom";

<Switch>
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
</Switch>;

此时,再访问/login 的时候,却只显示了 Home 组件。这个时候就需要用到 exact 属性了,他的作用就是精确匹配路径,经常与 switch 联合使用,只有当 url 和该 route 的 path 属性完全一致的时候才能匹配上

1
2
3
4
5
6
import { Switch, Route } from "react-router-dom";

<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/login" component={Login}></Route>
</Switch>;

在单页面应用中,往往需要在不同页面直接进行切换,这就使用到了 link 组件,link 组件为我们提供了一个声明式的,可访问的导航链接

1
2
import { Link } from "react-router-dom";
<Link to="/login">Login</Link>; // 会被解析成:<a href="/login">Login</a>
  • to:string | object:声明要导航到的链接地址,可以是一个字符串,也可以是一个对象
1
2
3
4
5
6
7
8
9
10
import { Link } from 'react-router-dom'

// 字符串形式
<Link to="/login?name=zhangsan#hash">Login</Link>
// 对象形式
<Link to="{{
pathname:'/login', // 要导航到的路径
search: '?name=zhangsan', // 查询参数
hash: '#hash' // 哈希
}}">Login</Link>
  • Replace:boolean:该属性决定是将点击后的链接替换历史堆栈中的最新消息,设置为 true 的时候是替换,设置为 false 的时候是添加。默认为 false
1
2
3
<Link to="/login" replace>
Login
</Link>

navlink 是特殊的 link,可以与当前 url 匹配的 link 元素添加样式属性。

  • activeclassname:string 表示当前元素处于激活状态时的类名,默认为 active
1
2
3
4
5
import { NavLink } from "react-router-dom";

<NavLink to="/login" activeClassName="active">
Login
</NavLink>;
  • activestyle:object 表示当前元素处于激活状态时的样式
1
2
3
4
5
import { NavLink } from "react-router-dom";

<NavLink to="/login" activeStyle={{ color: "red" }}>
Login
</NavLink>;
  • exact:boolean 设置为 true 时,当且仅当完全匹配时才应用 activeclassname 和 activestyle
1
2
3
4
5
import { NavLink } from "react-router-dom";

<NavLink exact to="/login">
Login
</NavLink>;
  • isactive:function 可以通过 isactive 添加一些额外的逻辑来决定当前链接是否处于激活状态
1
2
3
4
5
6
import { NavLink } from 'react-router-dom'

dealActive () {
...
}
<NavLink to="/login" isActive={dealActive}>Login</NavLink>

Redirect

路由重定向:

1
2
3
4
<Switch>
<Redirect from="/users/:id" to="/users/profile/:id" />
<Route path="/users/profile/:id" component={Profile} />
</Switch>

当请求/user/:id 被重定向去 /user/profile/:id

  • 属性 from:string:需要匹配的将要被重定向路径
  • 属性 to:string:重定向的 url 字符串
  • 属性 to:object:重定向的 loaction 对象
  • 数据 push:bool:若为真,重定向操作会把新地址加入到历史访问记录里面,并且无法回退到前面的页面

Promt

当用户离开当前页面做出一些提示,属性如下

  • 属性 message:string 当用户离开当前页面时,设置的提示信息
1
<Prompt message="确定要离开?" />
  • 属性 message:func 当用户离开页面时,设置回调函数
1
<Prompt message={(location) => `确定要去 ${location.pathname} ?`} />
  • 属性 when:bool 决定是否启用 Prompt

嵌套路由

嵌套路由是指在 Route 渲染的组件内部定义新的 Route,比如上面的 login 组件中可以再定义两个路由

1
2
3
4
5
6
7
8
9
const Login = ({match} => {
return (
// 这里 match.url 等于 /login
<div>
<Route path={`${match.url}/:id`} component={TestId} />
<Route exact path={match.url} component={Test} />
</div>
)
})

注意:嵌套路由是基于当前路由创建的路由,前缀是我们当前的路由

动态路由

假设,再增加一个新的页面叫 Product,对应路径为/produc,但是只有用户登录了之后才显示。如果用静态路由,我们在渲染之前就确定了这条路由规则,这样即使用户没有登录,也可以访问 product,我们还不得不在 product 组件中做用户是否登录的检查

如果用动态路由,则只需要在代码中的一处涉及这个逻辑:

1
2
3
4
5
6
7
8
<Switch>
<Route exact path='/' component={Home}/>
{
isUserLogin() &&
<Route exact path='/product' component={Product}/>,
}
<Route path='/about' component={About}/>
</Switch>

可以用任何条件决定 Route 组件是否渲染,比如可以根据页面的宽度,设备的类型来决定路由规则,动态路由就有了最大的自由度