React总结

一. react-router-dom

简介: React Router是一个基于 React 之上的强大路由库,它可让你向应用中快速地添加视图和数据流,同时保持页面与URL间的同步。html

router共包含如下几种:
react-router: React Router 核心
react-router-dom: 用于 DOM 绑定的 React Router
react-router-native: 用于React Native 的 React Router
react-router-redux: React Router 和 Redux的集成
react-router-config: 静态路由配置的小助手

说明:
今天咱们主要说的是 react-router-dom
react-router-dom包含 HisitoryRouter BrowserRouter等
注意:使用react-router-dom时,只须要引入react-router-dom就能够了,不须要引入react-router


<BrowserRouter>

使用

import { BrowserRouter, NavLink, Switch, Redirect} from 'react-router-dom'

<BrowserRouter basename={`${path}`}>
  <ul id="menu">
     <NavLink activeClassName={styles.active} exact to={`/`} />
     <NavLink activeClassName={styles.active} to={`/user`} />
  </ul>
  <div id='page-container' className={styles.container}>
   <Switch>
      <Route path={`/`} exact component={main} />
      <Route path={`/user`} render={(props) => <User pageId="user" />} />
      <Redirect to="/" />
    </Switch>
   </div>
</BrowserRouter>

// NavLink添加activeClassName属性以后可让首页tab默认选中
复制代码
<Switch>
    <Route exact path="/app/" render={() => 
    <Redirect to='/app/error'></Redirect>}></Route>
    <Route path="/app/users" component={Users}></Route>
    <Route path="/app/report" component={Report}></Route> 
    <Route path="/app/error" component={ErrorPage}></Route>
    <Redirect to="/app/" />
</Switch>

说明:
一、地址栏输入 /app/user ,跳转到指定的Users组件
二、exact指定输入 /app/重定向redirect to /app/error,重定向到ErrorPage组件中
3. 若是输入错误的地址,重定向到/app/路由,跳转到ErrorPage组件中
注意:重定向分两种 1.指定重定向,2.模糊重定向



复制代码

<Switch> 只渲染出第一个与当前地址匹配的<Route><Redirect>node

Switch解决的问题:若是你访问/about,那么与/about相关的路径都将被渲染出来,如/about/user,由于他们对应的路由与访问的地址/about匹配。这显然不是咱们想要的,咱们只想渲染出第一个匹配的路由就能够了,因而<Switch>应用而生!react

Historyredux

pushState()浏览器

popstate性能优化

路由实现 - history

<header>
  <a onclick="changeRoute(this)" data-path="home">首页</a>
  <a onclick="changeRoute(this)" data-path="center">我的中心</a>
  <a onclick="changeRoute(this)" data-path="help">帮助</a>
</header>
<section id="content"></section>
<script>
/**
Hisotory.pushState(state, title, url) 按指定的名称和URL(若是提供该参数)将数据push进回话历史栈。

state: 一个与添加的记录相关联的状态对象,主要用于popstate事件,该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化之后保留在本地,从新载入这个页面的时候,能够拿到这个对象。若是不须要这个对象,此处能够填为null

title: 新页面的标题。可是,如今全部浏览器都忽视这个参数,因此这里能够填空字符串。

url: 新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个地址。

*/
  function changeRoute (route) {
      let path = route.dataset.path
      
      changePage(path)
      history.pushState({content: path}, null, path)
  }
  /**

  当活动历史记录条目更改时,将触发popstate事件。history.pushState()的调用建立的,或者受到对 history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。
  
  history.pushState() 或者 history.replaceState()不会触发popstate事件。只有在作出浏览器动做时,才会触发该事件,如用户点击浏览器的回退按钮 或者在js代码中调用history.back()
  
  */
  window.addEventListener('popstate', (e) => {
      let content = e.state && e.state.content
      changePage(content)
  })
  
  function changePage (pageContent) {
      let content = document.getElementById('content')
      content.innerText = pageContent
  }
</script>
复制代码
  • BrowerRouterbash

    <BrowerRouter>使用HTML5的history API (pushStatereplacestate popstate事件)来同步URL和UI服务器

<BrowerRouter basename={optionalString} forceRefresh={optionlBool} getUserConfirmation={optionlFunc} keyLength={optionlNumber}>
<App/>
</BrowerRouter>
复制代码

属性介绍babel

basename: string:基准URL.适用于当应用置于服务器上子目录的状况下。数据结构

forceRefresh: bool: 当设为true时,每次跳转都会刷新页面。通常只在浏览器不支持HTML history API的状况下使用。

getUserConfirmation: func: 能够传入一个函数,用来肯定导航前的用户确认行为,默认使用window.confirm,以下:

keyLength: number: 设置location.key的长度,默认为6位

children: node:子元素里只能渲染单一的元素

  • HashRouter

    使用URL中的hash部分(即window.location.hash)来保持UI和URL同步

    注意:HashHistory不支持location.keylocation.state,因此任何须要这两个属性的代码或者插件将不能起做用。因为HashHisitory这种技术的主要目的是支持老式浏览器,因此官方更推荐的作法是对服务器进行配置,而后采用<BrowerRouter>代替。

  • MemoryRouter

    在内存中记录history的路由组件(这种路由不会读取或者写入地址栏),适合用于测试或者非浏览器环境(如ReactNative

导航跳转

  1. Link

为应用提供声明式、可访问的导航的一个组件:

import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
复制代码

参数: to: string 要跳转到的 pathname 或者 location

to: object

用法:

<Link to={{
      pathname: '/course', 
      search: '?sort=name',
      hash: '#the-hash',
      state: { fromDashboard: true }
}} />
复制代码

replace: bool 当这个值为 true 时,会替换掉history栈里当前的history,而不是在栈里新增一条history,如:

<Link to="/courses" replace>
复制代码
  1. NavLink

<Link>组件的特殊版本,当前URL匹配时,会在元素上增长样式相关的属性activeClassName,从而达到高亮标记的效果。

import { NavLink } from 'react-router-dom'
<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设为true时,只有当location彻底匹配的时候才会添加类名或者样式: 与Switch的区别

<NavLink exact to="/profile">Profile</NavLink>
复制代码

strict: bool:当设为 true时,location中pathname末尾的/就会在匹配URL的时候被考虑: 就是说有/和没有/的结果彻底不一样

<NavLink strict to="/events/">Events</NavLink>
复制代码

isActive: func:用来为link添加判断激活状态额外逻辑的函数,如:

isActive能够经过逻辑来控制

// 只有当事件ID为奇数时才可能为激活状态
const oddEvent = (match, location) => {
    if (!match) {
        return false
    }
    const eventID = parseInt(match.params.eventID)
    return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink to="/events/263" isActive={oddEvent}>Event 263</NavLink>
复制代码

location: object

isActive函数里用来比较用的值(即传入的第二个参数),一般状况下取值为当前浏览器的URL.若是要和不一样的location比较,就能够用这个属性来传值。

<NavLink activeClassName={styles.active} exact to={`/`} />
复制代码

二. Router、Route与Switch 一、Router 通用的基础路由组件。一般在应用里会采用派生的路由代替,有:

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

最经常使用的直接采用<Router>的场景是用状态管理库(Redux、Mobx)来同步一个自定义的history。不过应当注意的是:这不是说必须结合状态管理库使用ReactRouter,只是在深度集成的时候须要用到:

import { Router } from 'react-router'
import createBrowserHistory from 'history/createBrowserHistory'

const history = createBrowserHistory()
<Router history={history}>
    <App />
</Router>
复制代码

参数:

history: object 用来导航用的history对象

二、Route

组件也许是ReactRouter里最须要好好理解和使用的最重要的一个组件。它的基本职责是在location匹配路由的path参数值时渲染特定的UI:

import { BrowserRouter as Router, Route } from 'react-router-dom'
<Router>
    <div>
        <Route exact path="/" component={Home} />
        <Route path="/news" component={NewsFeed} />
    </div>
</Router>
复制代码

当location是/时,UI将会渲染为:

<div>
    <Home />
    <!-- react-empty: 2 -->
</div>
复制代码

而若是当UI是/news时,UI将会渲染为:

<div>
    <!-- react-empty: 1 -->
    <NewsFeed />
</div>
复制代码

react-empty注释,只是React的null渲染的实现。可是这种作法是有益的,从技术上而言一个Route应该老是被渲染出来即便结果是渲染null,而只要应用的location和Route的path匹配,那么对应的组件就会获得渲染。

2-一、路由渲染方法

渲染一个路由有三种方式:

<Route component> <Route render> <Route children>

每一种方式在不一样的情景下都是有用的,可是在<Route>里只能同时用一个属性,不过大部分状况下用的是component

注意: 因为优先级上:component > render > children,因此在<Route>里最多只能选用一种。

首先须要知道的是,这三种方式都会获得match、location、history这三个路由属性。

说明:

component方式,代表location匹配时要渲染的React组件,组件可使用路由属性来进行渲染:

<Route path="/user/:username" component={User} />

const User = ({ match }) => {
    return <h1>Hello, {match.params.username}!</h1>
}
复制代码

当使用这种方式时,路由系统会使用React.createElement来从给定的组件里建立一个新的React元素。这意味着若是传给component属性的是一个内联的函数,那么每次渲染时就都会 建立一个新的组件。这就会致使现有的组件卸载,而后挂载新的组件。而非更新已有的组件。因此要使用内联函数来进行内联渲染时,可使用render方式或者children方式

render: func方式,这种方式将方便于内联渲染,而且不会有上述的从新挂载问题。咱们能够传入一个函数,那么当location匹配的时候这个函数就会被调用,从而不会进行新的React元素建立过程。render属性接收和component属性一致的路由属性:

<Route path="/home" render={() => <div>Home</div>} />

const FadingRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
        <FadeIn>
            <Component {...props} />
        </FadeIn>
    )} />
)

<FadingRoute path="/cool" component={Something} />
复制代码

children: func方式,有时候,不管path是否成功匹配都须要进行渲染。那么这种状况下,可使用children属性方式,这种方式不管匹配是否成功都会调用对应的函数。 而children渲染属性接收和component、render方式同样的属性,不过当路由不匹配的时候,match的值是null。因此采用这种方式的好处是,咱们能够灵活地动态调整UI,不管路由是否匹配。举例如:

路由匹配时添加激活状态的类名:

<ul>
    <ListItemLink to="/somewhere" />
    <ListItemLink to="/somewhere-else" />
</ul>

const ListItemLink = ({to, ...rest}) => (
    <Route path={to} children={({ match }) => (
        <li className={match ? 'active' : ''}>
            <Link to={to} {...rest} />
        </li>
    )}/>
)
复制代码

对于动画而言,这种方式也是有用的:

<Route children={({ match, ...rest }) => (
    // 由于动画会一直渲染,因此可使用生命周期来让子元素动画进出
    <Animate>
        {match && <Something {...rest}/>}
    </Animate>
)}
复制代码

三、Switch

渲染子元素里第一个匹配的<Route>或者<Redirect>,那么,和只使用一堆<Route>不一样的是什么? <Switch>独一无二的是它只渲染一个路由。而反过来,每一个匹配location的<Route>都会被获得渲染,参考以下代码:

<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={NoMatch} />
复制代码

若是URL是/about,那么<About><User><NoMatch>都会渲染,由于它们的path都获得了匹配。而这种设计是有意的,由于这使得咱们能够用多种方式来用<Route>组成咱们的应用,如侧边栏、面包屑、引导Tab等。

不过有时候,咱们只想要拾取一个<Route>来渲染,就好比URL处于/about时就不但愿它匹配/:user(或者展现404页面),如:

import { Switch, Route } from 'react-router'
<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/:user" component={User} />
    <Route component={NoMatch} />
</Switch>
复制代码

如今,若是URL是/about,那么<Switch>就会开始寻找匹配的<Route><Route path="/about"/>将会匹配,从而<Switch>就会中止匹配而后渲染出<About>组件。类似地,若是URL处于/michael,那么<User>组件就会渲染。

对于动画过渡而言,这也是一种有用的方式,由于匹配的<Route>须要渲染在先前相同的位置:

<Fade>
    <Switch>
        {/* 这里只会有一个子节点 */}
        <Route/>
        <Route/>
    </Switch>
</Fade>

<Fade>
    <Route/>
    <Route/>
    {/* 
        这里一直都会有两个子节点,尽管其中一个可能为null,
        这会使得过渡效果起效果有点难处理
    */}
</Fade>
复制代码

参数说明:

location: object 和以前其余地方里含义一致 children: node <Switch>组件的子元素都应该是<Router>或者<Redirect>,而且只有匹配当前URL的第一个子元素会被渲染。其中,<Route>元素使用path属性来进行匹配,而<Redirect>使用from属性进行匹配。而不带path属性的<Route>元素或者不带from属性的<Redirect>元素会老是匹配当前location 因此当在<Switch>里使用<Redirect>组件时,它可使用和<Route>同样的匹配属性:path、exact、strict,而from只是path属性的别名。

当给<Switch>传入location属性时,会覆盖当前匹配的子元素中的location

<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/users" component={Users} />
    <Redirect from="/accounts" to="/users" />
    <Route component={NoMatch} />
</Switch>
复制代码
  1. redux
异步获取数据
复制代码
  1. 高阶组件
复制代码
  1. 程序设计
在接口的设计上应体现出数据与业务的相分离。下降耦合性。在代码的设计上也要尽可能下降重复性代码。在写代码以前要清楚接口的数据结构,设计好代码结构,尽可能减小在写代码时候频繁修改代码。
复制代码
  1. dangerouslySetInnerHTML

7.API

react中最重要的三个API: createElement 、render、 component

component(react中一切皆组件)中包含setState

virtual Dom

jsx表面看是HTML标签,其实是下面这套内容

React.createElement(
"div",
null,
"hello ",
this.props.name,
" ,I am",
{2 + 2},
"years old"
)
复制代码

是jsx的babel作的编译,jsx表面是html,其实是js

React.createElement返回的数据

JSX本质上就是转换为React.createElement在react内部构建虚拟dom,最终渲染出页面

React.createElement是用来建立虚拟DOM的

React.createElement是一个递归调用的过程,也就是说dom中嵌套dom,会嵌套相应个数的React.createElement

学习一个库的最好方法,先开发一个小应用,而后尝试理解源码。

参考连接:ReactRouter4学习笔记

2、分析执行流程

<div>
  <A />
  <B>
    <C />
    <D />
  </B>
</div>
复制代码

请说出componentWillUpdatecomponentDidUpdateA B C D四个组件的执行顺序。

  1. componentWillMount
A B C D
复制代码
  1. componentDidMount
A C D B
复制代码

3、PureComponent

原理:当组件更新时,若是组件的props和state都没发生改变,render方法都不会触发,省去Virtual DOM的生成和对比过程,达到提高性能的目的。React自动帮咱们作了一层浅比较。 PureComponent真正起做用的,只是在一些纯展现组件上,复杂组件使用的话shallowEqual那一关基本就过不了。

shouldComponentUpdate

React性能优化

不可变数据的力量,返回新对象,而不是修改老对象。

大部分状况下,可使用 React.PureComponent 来代替手写 shouldComponentUpdate。

4、setState

  1. setState只在合成事件和钩子函数中是"异步"的,在原生事件和setTimeout中都是同步的。
  2. setState的"异步"并非说内部由异步代码实现,其实自己执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新以前,致使在合成事件和钩子函数中无法立马拿到更新后的值,造成了所谓的“异步”,也能够经过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
  3. setState的批量更新优化也是创建在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout中不会批量更新,在“异步”中若是对一个值进行屡次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,若是是同时setState多个不一样的值,在更新时会对其进行合并批量更新。

5、readux-thunk中间件原理

redux-thunk为何能让action发送函数 redux-thunk是对dispatch方法作一个升级,以前这个dispatch方法只能接收一个对象,升级以后,就能够接收函数了。根据参数的不一样执行不一样的事情,若是是对象就直接传递给store,若是是函数就先执行函数,在调用dispatch。原理就是对store的dispatch方法作了一个升级。

4、Props.childern

相关文章
相关标签/搜索