reconciliation(协调算法)

react用于更新DOM的算法。基于两点假设,实现了一个启发的O(n)算法:

  1. 两个不同类型的元素将产生不同的树。
  2. 通过渲染器附带key属性,开发者可以示意哪些子元素可能是稳定的。

元素的不同类型

当对比两棵树时,React首先比较两个根节点。每当根元素有不同类型,React将卸载旧树并重新构建新树。

当树被卸载,旧的DOM节点将被销毁。组件实例将会接收到componentWillUnmount()方法。当构建一棵新树,新的DOM节点被插入到DOM中。组件实例将接收到componentWillMount()以及之后的componentDidMount()。任何有关旧树的状态都将被丢弃。

例如,在进行对比:

<div>
<Counter />
</div> <span>
<Counter />
</span>

这将会销毁旧的Counter并重装新节点。

相同类型的DOM元素

当比较两个相同类型的React DOM元素时,React则会观察二者的属性,保持相同的底层DOM节点,并仅更新变化的属性。(比如说变化的类名、样式等)

在处理完DOM元素后,React递归其子元素。

递归子节点

默认时。当递归DOM节点的子节点,React仅在同一时间点递归两个子节点列表,并在有不同时产生一个变更。

例如,当在子节点末尾增加一个元素,两棵树的转换效果很好:

<ul>
<li>first</li>
<li>second</li>
</ul> <ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>

React将会匹配两棵树的

  • first
  • ,并匹配两棵树的

  • second
  • 节点,并插入

  • third
  • 节点树。

    若原生实现,在开始插入元素会使得性能更棘手。例如,两棵树的转换效果则比较糟糕:

    <ul>
    <li>Duke</li>
    <li>Villanova</li>
    </ul> <ul>
    <li>Connecticut</li>
    <li>Duke</li>
    <li>Villanova</li>
    </ul>

    React会调整每个子节点,而非意识到可以完整保留

  • Duke
  • Villanova
  • 子树。低效成了一个问题。

    Keys

    为解决该问题,React支持了一个key属性。当子节点有key时,React使用key来匹配原本树的子节点和新树的子节点。例如,增加一个key在之前效率不高的样例中能让树的转换变得高效:

    <ul>
    <li key="2015">Duke</li>
    <li key="2016">Villanova</li>
    </ul> <ul>
    <li key="2014">Connecticut</li>
    <li key="2015">Duke</li>
    <li key="2016">Villanova</li>
    </ul>

    现在React知道带有'2014'的key的元素是新的,并仅移动带有'2015'和'2016'的key的元素。

    权衡

    由于React依赖于该启发式算法,若其背后的假设没得到满足,则其性能将会受到影响:

    1. 算法无法尝试匹配不同组件类型的子元素。若你发现两个输出非常相似的组件类型交替出现,你可能希望使其成为相同类型。实践中,我们并非发现这是一个问题。
    2. Keys应该是稳定的,可预测的,且唯一的。不稳定的key(类似由Math.random()生成的)将使得大量组件实例和DOM节点进行不必要的重建,使得性能下降并丢失子组件的状态。

    Portals

    Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。

    ReactDOM.createPortal(child, container)

    第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或碎片。第二个参数(container)则是一个 DOM 元素。

    用法

    通常讲,当你从组件的 render 方法返回一个元素,该元素仅能装配 DOM 节点中离其最近的父元素

    render() {
    // React mounts a new div and renders the children into it
    return (
    <div>
    {this.props.children}
    </div>
    );
    }

    然而,有时候将其插入到 DOM 节点的不同位置也是有用的:

    render() {
    // React does *not* create a new div. It renders the children into `domNode`.
    // `domNode` is any valid DOM node, regardless of its location in the DOM.
    return ReactDOM.createPortal(
    this.props.children,
    domNode,
    );
    }

    对于 portal 的一个典型用例是当父组件有 overflow: hidden 或 z-index 样式,但你需要子组件能够在视觉上“跳出(break out)”其容器。例如,对话框、hovercards以及提示框。

    通过 Portals 进行事件冒泡

    尽管 portal 可以被放置在 DOM 树的任何地方,但在其他方面其行为和普通的 React 子节点行为一致。如上下文特性依然能够如之前一样正确地工作,无论其子节点是否是 portal,由于 portal 仍存在于 React 树中,而不用考虑其在 DOM 树中的位置。

    这包含事件冒泡。一个从 portal 内部会触发的事件会一直冒泡至包含 React 树 的祖先。

    React拾遗(下)的更多相关文章

    1. [RN] React Native 下拉放大动画

      React Native 下拉放大动画 经测试,无法运行 https://www.jianshu.com/p/1c960ad75020

    2. [RN] React Native 下实现底部标签(支持滑动切换)

      上一篇文章 [RN] React Native 下实现底部标签(不支持滑动切换) 总结了不支持滑动切换的方法,此篇文章总结出 支持滑动 的方法 准备工作之类的,跟上文类似,大家可点击上文查看相关内容. ...

    3. react框架下,在页面内加载显示PDF文件,关于react-pdf-js的使用注意事项

      react框架下,在页面内加载显示PDF文件,关于react-pdf-js的使用注意事项 之前做了一个需求,在注册账号的时候,让用户同意服务条款, 服务条款是一个PDF文件, 这就需要在react内加 ...

    4. React视角下的轮播图

      天猫购物网站最显眼的就是轮播图了.我在学习一样新js库,一个新框架或新的编程思想的时候,总是感叹"入门必做选项卡,进阶须撸轮播图."作为一个React组件,它是状态操控行为的典型, ...

    5. react native下android开发环境搭建

      关于react native环境搭建我也是参考这篇文章的,但我这里就出现了很多在这篇文章里没有出现的问题,也是坑比较多.但最后在一位大神的帮助下还是成功运行了. 1.第一个坑就是有些文件下载需要VPN ...

    6. [RN] React Native 下实现底部标签(不支持滑动切换)

      底部标签是现在App的基本菜单实现 下面分别用 createBottomTabNavigator 和 createMaterialBottomTabNavigator 两种方法分别实现底部菜单 但此两 ...

    7. React拾遗(上)

      JSX代表Objects Babel转义器会把JSX转换成一个名为React.createElement()的方法调用. 下面两种代码的作用是完全相同的: const element = ( < ...

    8. [RN] React Native 下列表 FlatList 和 SectionList

      1.FlatList FlatList组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同. FlatList更适于长列表数据,且元素个数可以增删.和ScrollView不同的是,Fla ...

    9. react ie10下报错

      解决办法: 加 promise polyfill 参考地址:http://hao.jser.com/archive/12066/

    随机推荐

    1. WinServer-SMTP服务

      摘要 SMTP服务是用来发送邮件的,常用于代码中发送邮件,不能接收.本章介绍SMTP服务的安装,配置. 搭建F5负载均衡集群注意事项: 1.集群不能与exchang在同网段,否则发不出邮件. 2.AP ...

    2. c# List<Object>和List<实体>相互转化

      开发的过程中总会遇到各种转化的问题,现在我做的开发接口中就遇到需要将List<Object> 中的Object又含有List<实体>归为一个list中,就是要list中没有Li ...

    3. IO五种模型和select与epoll工作原理(引入nginx)

      用户速度体验的1-3-10原则 性能影响 有很多研究都表明,性能对用户的行为有很大的影响: 79%的用户表示不太可能再次打开一个缓慢的网站 47%的用户期望网页能在2秒钟以内加载 40%的用户 ...

    4. Linux命令——killall 、kill 、pkill、xkill

      参考:killall .kill .pkill 命令详解 Using kill, killall, and pkill 4 Ways to Kill a Process – kill, killall ...

    5. 【kernel】Centos 云上升级内核失败 如何处理【笔记记录转】

      Centos7选定默认启动的内核版本 vim /etc/grub2.cfg   修改timeout =5   修改成30天 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附 ...

    6. Redis4.0之持久化存储

      一,redis概述与实验环境说明 1.1 什么是redis redis是一种内存型的NoSQL数据库,优点是快,常用来做缓存用  redis存储数据的方法是以key-value的形式  value类型 ...

    7. LearnOpenGL学习笔记(二)纹理

      开始学习OpenGL,参考的是著名的LearnOpenGL这个网站,在这里做一些总结性的记录,只是方便自己日后查找或者记录自己的一些拓展思考,关于OpenGL的具体内容请移步: https://lea ...

    8. 树状数组例题-数星星,简单题easy,校门外的树2,清点人数

      [例1]数星星 天空中有一些星星,这些星星都在不同的位置,每个星星都有个坐标,如果一个星星的左下方(包括正左和正下)有k颗星星,就说这颗星星是k级的. 比如,上图中,星星5是3级的(1,2,4在其左下 ...

    9. echo 显示命令

      echo 显示命令 echo 是在PHP里面最常用的一个输出.显示功能的命令.直线电机滑台 我们可以让他显示任何可见的字符. <?php echo 123; ?> <?php $ip ...

    10. 学到了林海峰,武沛齐讲的Day19 迭代细讲

      在家加1个月学了8day的课  出差6天看了8day的课..说明再忙也是可以挤挤多学习的. 广州出差最后两天没学习.一天做车,一天做公司的事...4天就过去了. 老师讲的包子和鸡蛋需求不好...讲的有 ...