React-router4详解 看完你就懂了

React-router4详解 看完你就懂了

React-router4(RR4)

组成部分:

react-router 核心

react-router-dom(基于浏览器环境的开发)

react-router-native(基于react-native环境的开发)

  • 安装 react-router-dom 或 react-router-native 时,都会自动将 react-router 作为依赖安装

常用组件:

路由类型组件:(历史路由和哈希路由)


类似于vue中的history路由,利用了pushState和replaceState来构建路由。pushState和replaceState是HTML5新接口,可以改变网址(存在跨域限制)而不刷新页面,这个强大的特性后来用到了单页面应用如:vue-router,react-router-dom中。

  • 问题:在React + React-router实现的SPA(单页面应用)项目中,当我们路由模式采用browserHistory时,点击每个导航都可以显示正确的页面,一旦浏览器刷新,页面就显示Cannot GET(404)。
  • 分析:当刷新页面时,浏览器会向服务器请求example.com/list,服务器实际会去找根目录下list.html这个文件,发现找不到,因为实际上我们的服务器并没有这样的物理路径/文件或没有配置处理这个路由,所有内容都是通过React-Router去渲染React组件,自然会报404错误。这种情况我们可以通过配置Nginx或通过自建Node服务器来解决。
  • 解决:需要服务器支持(服务器配置)
  • 原理:其本质的原理就是利用服务端将任何请求都指向index.html,而在React应用中index.html又刚好通过React-Router配置了相应的路由,我们让服务器返回index.html,后面就交给前端路由来实现无刷新加载对应页面。
import  {BrowserRouter,Route,Switch} from 'react-router-dom'
<BrowserRouter>
<Switch>
	<Route path='/xxx' component={xxxx}>
 Switch>
BrowserRouter>


类似于vue中的hash路由,使用window.location.hash和hashchange事件构建路由。

hash即URL中"#"字符后面的部分。

  • 使用浏览器访问网页时,如果网页URL中带有hash,页面就会定位到id(或name)与hash值一样的元素的位置;
  • hash还有另一个特点,它的改变不会导致页面重新加载;
  • hash值浏览器是不会随请求发送到服务器端的;
  • 通过window.location.hash属性获取和设置hash值。

hashchange事件(IE8已支持该事件)

  • 当URL的片段标识符更改时,将触发hashchange事件(跟在#符号后面的URL部分,包括#符号)
  • hashchange事件触发时,事件对象会有hash改变前的URL(oldURL)和hash改变后的URL(newURL)两个属性。
import  {HashRouter,Route,Switch} from 'react-router-dom'
<HashRouter>
<Switch>
	<Route path='/xxx' component={xxxx}>
Switch>
HashRouter>

路由渲染组件:

是 React Router 中最重要的组件,它最基本的职责就是:当页面的访问地址与 Route 上的 path 匹配时,就在`所在位置渲染出对应的组件并且往组件props注入history,location,match参数

<Route path="/home" component={Home} />

属性:

  • path(String):当浏览器地址与path地址匹配时,则渲染component对应的组件
  • component(Component):在path匹配成功之后会渲染这个组件
  • render(Function):在path匹配成功之后会渲染这个函数返回的内容
  • exact(Boolean):是否精确匹配

 <Route path="/home" component={Home}/>

 <Route path="/home" component={Home} exact /> 

动态路由

  • 在匹配路径path的后面加上冒号 + 参数, 如`path =“goods/:id”。
  • 获取动态id方式:
    当通过渲染组件时,路由会给我们组件注入3个参数(history,location,match),通过match.params获取动态路由参数。

嵌套路由

在使用嵌套路由时在父级不能使用exact,因为当匹配路由时加了子路由路径会导致父路由路径不能被匹配到,从而父子组件都显示不了。

实现的两种方式

  1. 在组件中需要嵌套路由的地方直接使用Route标签书写路由
<Router>
 <App>
   <Switch>
    <Route path="/home" component={Home}>Route>
   Switch>
 App>
Router>


<div>
<Route path="/home/menu" component={Menu}>Route>
div>
  1. 使用render函数直接渲染嵌套路由
<Router>
<App>
<Switch>

     <Menu>
         <Route path="/home/menu" component={Menu}>Route>
     <Menu/>
 }>
Route>
Switch>
App>
Router> 

  • 用于重定向页面

属性:

  • from(String):浏览器地址为from的值时,重定向到to所在的地址
  • to(String|Object):跳转的地址(如值为Object,有以下参数)
    • pathname,跳转到的URL。
    • search,跳转后的url参数。
    • state,会保存在this.history.location.state中,可以用于传递数据
  • 渲染第一个被匹配到的并且作为子元素的**或者**

<Route path="/index" component={Home} />
<Route path="/:user" component={Home} />
<Route component={List} />

<Switch>
<Route path="/" component={Home} />
<Route path="/home" component={Home} />
<Route path="/list" component={List} />
<Redirecct to="/404"/>
Switch>

上例中有个问题就是当我们url输入为/list时,渲染的竟然是Home组件,而不是List组件。其实答案就在’Switch只渲染第一个被匹配到的组件’,对, 只找到第一个被location匹配到的就立即停止继续匹配,并且把它渲染出来。"/list"同时和"/","/list"相匹配,因为先匹配到了前者,所以只有Home组件被渲染。
虽然可以通过顺序的调整得到想要的结果,但是难道每次我们写路由的时候都要严格控制书写顺序吗?不,还记得有个exact属性吗?当添加exact属性后只有URL和该的path属性进行精确比对后完全相同该才会被渲染。


<Switch>
<Route path="/" exact component={Home} />
<Route path="/home" component={Home} />
<Route path="/list" component={List} />
<Redirecct to="/404"/>
Switch>

导航:

​ 声明式导航:(利用Link或NavLink组件属性实现路由跳转)

点击转跳到指定路径

  • 默认解析成a标签

  • 属性

    to(Object):携带参数跳转到指定路径(同Redirect)

    
    

    to(String): 点击跳转到指定路径

    <Link to="/home" />
    

    replace(bool):为 true 时,点击链接后将使用新地址替换掉上一次访问的地址

顾名思义这就是为页面导航准备的。因为导航需要有 “激活状态”(高亮)

  • 属性

    • activeClassName(String)

      导航选中激活时候应用的样式名,默认样式名为 active

    • activeStyle(Object)

      如果不想使用样式名就直接写style

    • to: string|object

    • isActive: func
      通过返回值(boolean)决定导航是否激活,或者在导航激活时候做点别的事情。不管怎样,它不能决定对应页面是否可以渲染。

​ 编程式导航:(利用路由提供的history对象实现路由跳转)

  • history.push(path|Object):向history栈里面添加一条新记录,这个时候用户点击浏览器的回退按钮可以回到之前的路径。
  • history.replace(path|Object):不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。

获取history对象的方法:

利用组件

  • 在使用React-router时,利用的方式渲染我们的组件时histroy对象会被自动传入组件的props中。

高阶函数withRouter(推荐)

  • 组件在被withRouter高阶组件包装后,在组件中可直接通过props.history获取,然后就可以使用编程式导航进行点击跳转了。

history扩展
如果你想要理解React-router,首先要学习history,更准确的说就是这个为React-router提供了核心功能的history库。说道history库大家一定觉得很熟悉,因为在HTML5中也有一个同名的history对象。
那么这个HTML5中的history对象解决了什么问题呢?
在jQuery盛行的时期,大家常通过ajax请求来达到无刷新更新页面的目的(SPA雏形)。为了使页面在刷新后仍能正确的显示页面的元素,一般会通过改变url的hash值来定位发生变化后的页面。但是这会带来一个问题:用户无法通过前进/后退按钮来切换页面。在这种大环境下histroy对象应运而生。当页面的url或者hash发生改变时,浏览器会自动将新的url放到history对象中。history对象中有一个用来记录url变化的state数组。在浏览器中进行前进/后退操作时,实际上就是使用history对象中对应的方法forward/back,取出state中的数据来达到切换页面的效果。
除此之外,history还提供了不用操作url就能更新内部state数组状态的方法:pushState和replaceState。

那么histroy库又是什么呢?
history库借鉴了H5的history对象的理念,在其基础上拓展了一些功能。
1.它提供了3种类型的history,分别用于创建browser,hash,memory类型的历史信息。
import {createBrowserHistory, createHashHistory, createMemoryHistory} from 'history'
2.它支持发布/订阅功能 (listen)
3.提供了跳转拦截,跳转确认等实用的功能 (block)
对比以上两个history的属性:

const histroy={						const h5history={
  length,									length,
  action,									state,
  location,									pushState,
  push,						    			replaceState,
  replace,							
  go,							    		go,	
  goBack,									back,	
  goForward,								forward,
  canGo,									}
  block,
  listen
}

可以说histroy库是history对象的超集,是功能更强大的history对象。

如果你使用了React router,它会自动为你创建history对象,这样你就不需要真正的去跟history打交道。但是,去理解各种类型的history还是很重要的,这样你就能够决定哪一种才是真正适合你的项目的。

react-router的生命周期

相比之前的版本,RR4有了很大的改变,废除了之前版本onEnter、onLeave等路由钩子函数,利用组件生命周期函数来替代

  • 使用componentDidMount来代替onEnter
  • 使用componentDidUpdate来代替onUpdate
  • 使用componentWillUnmount来代替onLeave

你可能感兴趣的:(React,reactjs)