markdown 反应路由器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown 反应路由器相关的知识,希望对你有一定的参考价值。

## 概述
react-router是用于实现React项目中路由功能的库,对于构建SPA React项目非常有必要,react-router4.x对react-router整体进行了重写,API也相对于3.x有了很大的改变,可以理解4.x和3.x是两个完全不同的工具,3.x主张集中配置route,4.x则将每一个路由都当做普通React component,因此route的配置会融入到整个项目的代码中,它的作者把这个称之为动态路由。这里重点介绍react-router4.x的使用。

## 安装
react-router将之前的库拆分成以下三个库:
* react-router:react-router的核心代码;
* react-router-dom:Dom绑定的react-router,依赖react-router;
* reat-router-native:react native绑定的react-router,依赖react-router;

对于react项目,我们只需要安装 react-router-dom即可:

```sh
npm install react-router-dom --save
```

## Router
react-router提供好几种router来满足不同的需求:
* BrowserRouter:使用传统网站方式的路由,用path来指定不同路由,对于这种Router,需要在服务端进行设置将所有路由范围内的请求指向到一个静态Html;
* HashRouter:使用hash值来指定不同路由,对于使用static形式来作为服务端的情况,用这种router非常方便,不需要服务端做任何额外的配置;
* MemeryRouter:将路由指定存放在内存中,通常用于测试环境、没有浏览器的环境或者是react native;
* StaticRouter:用于不需要改变location的router;

其中使用最多的是BrowserRouter和HashRouter,这里用HashRouter举例:
```js
import {HashRouter} from 'react-router-dom';

ReactDOM.render((
  <HashRouter>
    <App />
  </HashRouter>
), document.getElementById('root'))
```

## Route
Route组件是react-router中最重要也是最常用的组件,它通常的作用是当url和组件的path属性匹配时渲染相应的UI组件。

Route可以通过3种方式来指定UI:
* ```<Route component>```

```js
import {Route} from 'react-router-dom';
import Page1 from './page1';

export default (props) => {
  return (
    <div>
      <Route path="/page1" component={Page1} />
    </div>
  );
}
```
> 这种方式其实是route通过React.createElement来创建一个component指定组件的实例,需要注意的是如果component组件传入一个inline函数来返回一个组件,那么每次render就会创建一个新的实例,这样就导致已有的组件实例没有销毁,新的实例又创建了,而不是直接更新已有的实例,因此对于这种情况,建议使用下面两种方式。

* ```<Route render>```

```js
import {Route} from 'react-router-dom';

export default (props) => {
  return (
    <div>
      <Route path="/page2" render={(props) => (
          <div>
            page2 yoyoyo
          </div>
        )} />
    </div>
  );
}
```

* ```<Route children>```
通过children属性来指定UI组件,接受一个参数为match的函数,使用者可以根据是否匹配path来选择渲染不同的UI组件。

```js
import {Route} from 'react-router-dom';

export default (props) => {
  return (
    <div>
      <Route path="/page2" children={({match}) => {
        if (match) {
          return (<div> match the path</div>);
        } else {
          return (<div> not match the path</div>);
        }
      }} />
    </div>
  );
}
```

Route组件可以配置如下参数来指定url匹配规则:
* path:string类型,[path-to-regexp](https://www.npmjs.com/package/path-to-regexp)形式,用于指定需要匹配的path,若不指定,表明匹配所有的path;
* exact:bool类型,用于指定完全匹配path,如下所示:

|path|location.pathname|exact|match?|
|-|-|-|-|
|/one|/one/two|false|yes|
|/one|/one/two|true|no|

* strict: bool类型,若设置为true且path末尾跟一个‘/’,那么只能匹配后面跟有‘/’的pathname,若设置为true,如下所示:

|path|location.pathname|match?|
|-|-|-|-|
|/one/|/one|no|
|/one/|/one/|yes|
|/one/|/one/two|yes|

* location: object类型,默认情况下Route会匹配当前浏览器中的location,通过location我们可以自定义一个location来用于匹配;

Route在指定渲染UI组件时会给组件注入3个props:
* match:是一个用描述match情况的对象,主要包含以下内容:
  * params:key/value对,用于记录path中变量的值,例如/page/:id中的id;
  * isExtract:bool类型,表示是否绝对匹配;
  * path:string类型,进行匹配的path,通常用于嵌套route的时候;
  * url:string类型,匹配的URL部分,通常用于嵌套link的时候;

* location:用于记录当前location相关描述,通常是下面这个样子:

```js
{
  key: 'ac3df4', // not with HashHistory!
  pathname: '/somewhere'
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}
```
> 在history的属性中也有一个history.location,但是通常建议使用这个,因为history下面的location会发生突变,这个不会。

* history:history用于记录history相关的描述,主要包含以下属性:
  * length:history栈中的实体数量;
  * action:指明当前的action(PUSH、POP或REPLACE);
  * location:同上面介绍的location;
  * push:push一个新的实体到history栈中;
  * replace:替换history栈中的当前实体;
  * go:移动history栈中当前实体的指针;
  * goBack:相当于go(-1);
  * goForward: 相当于go(1);
  * block: 阻止导航;
  
## Redirect
用于将当前locaction重定向到一个新的location,新的location将替换掉history栈中的当前实体。通常用法:

```js
//接受string
<Redirect push to="/somewhere/else"/>
//接受object
<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
//在switch中使用
<Switch>
  <Redirect from='/old-path' to='/new-path'/>
  <Route path='/new-path' component={Place}/>
</Switch>
```

## Switch
Switch用来包裹Route和Redirect,并render第一个匹配的Route或Redirect。因此它是有排他性的,不使用switch的情况下,会渲染所有匹配的Route或Redirect。

如下所示,如果访问/about,三个组件都会被渲染:

```js
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
```

如果按照下面的方式来写,往往更能达到用户的期望:

```js
<Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>
```

> Switch中只能使用Route和Redirect子元素

> Switch可以设置一个location熟悉来替代当前浏览器location

> 没有path的Route和没有from的Redirect都可以匹配所有链接

## Link & NavLink
Link类似a标签,用于进行页面跳转,默认是使用push的方式,通常用法如下所示:

```js
<Link to="/courses"/>

<Link to={{
  pathname: '/courses',
  search: '?sort=name',
  hash: '#the-hash',
  state: { fromDashboard: true }
}}/>

<Link to="/courses" replace />
```

NavLink是一种特殊的Link,它可以将样式属性传递给当前组件,如果to设置的path匹配当前URL,最常见的场景就是导航条。基本用法如下:

```js
//设置class
<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>

//设置属性
<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red'
   }}
>FAQs</NavLink>

//支持exact和strict属性
<NavLink
  exact
  strict
  to="/profile/"
>Profile</NavLink>
```
我们也可以设置一个isActive属性来处理一些特殊逻辑:

```js
const oddEvent = (match, location) => {
  if (!match) {
    return false
  }
  const eventID = parseInt(match.params.eventID)
  return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
  to="/events/123"
  isActive={oddEvent}
>Event 123</NavLink>
```

## 参考
* https://reacttraining.com/react-router/web/example/basic
* https://medium.com/@pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf

以上是关于markdown 反应路由器的主要内容,如果未能解决你的问题,请参考以下文章

markdown 反应路由器

markdown 反应-路由器页面不更新

markdown 反应路由器

markdown 反应路由器我的自定义导航练习

markdown Vue反应系统

markdown 反应数格式器