一、自述
开发之路断断续续使用过React-Native用于开发项目。虽然更多专注与需求的快速开发,很多使用的技术也都只是了解后直接使用,简直有些无脑。但是需求已经完成,开发也已经结束,在此也需要进行一次复盘。
作为一直使用强语言,而第一次使用弱语言(JavaScript)开发的我,简直是对其感到害怕,没有完整编辑器、代码提示、页面显示效果、更没有对 React-Native 有深入的了解下就使用 Redux 进行状态维护。没错,我从入门到跑路,抵触的心从一开始就深深扎入。
WebStore、VS-Code、Vim。编辑器也是不停的转换,来渴望在开发过程中,找到强语言时开发的感觉。
ES6、Flex、Redux、Immutable。React的学习也是不停的深入,也使作为小白的我有了不同的心态和看法。
所有文章也只是我的个人看法和了解,也会不停的更新。
二、React
JSX
JSX作为React的核心语言部分,使用XML标记的方式直接声明界面。var React = require(‘React’);
var message =
<div class=“hello” onClick={someFunc}>
<span>Hello World</span>
</div>;
React.renderComponent(message, document.body);
据说此次的嵌入组合相对于JavaScript也是接近于疯狂的事情,将界面与业务分离的理念也被再一次颠覆。但是在熟悉开发后发现,此方式更直观的降低React的开发学习门槛,代码也极容易理解。
状态机
而使JSX更直观的原因就是React的理念为一个状态机。组件的开发已经是很早就推荐的开发方式,用于提高复用和精简组件间逻辑的目的。但是React的组件却与之不同:
所谓组件,就是状态机器
React 将用户界面看做简单的状态机器。当组件处于某个状态时,那么就输出这个状态对应的界面。通过这种方式,就很容易去保证界面的一致性。
在 React 中,你简单的去更新某个组件的状态,然后输出基于新状态的整个界面。React 负责以最高效的方式去比较两个界面并更新 DOM 树。
setState
对组件的管理就是对状态的管理。其不同与其他框架或多或少的会双向交互、数据返回的必要性(当然React也因需求需要该功能)。在React中,我们只需要setState({...})
来完成对组件的状态进行更改,而相应UI的显示与其状态进行绑定,也就解决了逻辑与UI的通信问题。
Props
在React中组件可以作为基本单位,而在交互中除了 State(状态)外,还有就是 Props(属性)。State 更像是组件内部的自状态管理,完成对自己内部UI的控制,而Props则在对组件进行初始化中,完成了其相应功能,因此在相较于State的状态可改变,Props则推荐不可改变的数据,只用于读取。this.state = {
btnState: this.props.btnState
};
页面刷新
可以看到React是一个两层的编程模型:数据模型驱动 UI 界面。在数据变动后完成UI界面的变动(刷新)。刷新更像是对页面的刷新描述,当然也确实是。但是在界面及其复杂的时候,只是为了变动一个小小的参数,而刷新整个页面,代价实在太大了。因此为了解决这个问题,React使用局部UI组件刷新的概念。
由于组件的出现,完成了UI的逻辑状态的自管理。而完成这些组件的自刷新就是:虚拟DOM(Virtual DOM)。这个词相较于了解React的各位相信都很清楚:
简而言之就是,UI 界面是一棵DOM 树,对应的我们创建一个全局唯一的数据模型,每次数据模型有任何变化,都将整个数据模型应用到UI DOM 树上,由React 来负责去更新需要更新的界面部分。
这使得React极大的提高性能,也将”组件化”这一理念更执行的透彻。
单向数据流-Redux
只有遇到React实在解决不了的问题,你才需要Redux。
虽然使用state来进行自身状态管理。但是在大型项目时会发现React的通信机制依旧无法满足大型项目,也就需要Redux来完成更庞大的数据通信。
Redux是一个数据流管理框架,与React最大相同点他们都偏向单项数据流,因此更符合React的数据管理理念。
Immutable
用于建立一个数据模型,用于对特殊数据的管理(只读数据)。面对网络请求后立即加载至UI,使代码更有利于维护性、安全性。
三、虚拟DOM
Web页面都是由DOM树而来。React会根据当前的状态来决定界面。当DOM某个节点发生变化,就会生成一个新的状态DOM,将两者进行比较,选择变化后的DOM树完成新的界面映射。这就需要对DOM树的Diff算法分析。
在发生上述状况下一般由两者情况需要刷新DOM树:
1.节点类型不同(节点ID不同)
2.节点类型相同,但是属性不同
节点类型不同
当在树中的同一位置前后输出了不同类型的节点,React 直接删除前面的节点,然后创建并插入新的节点。
当删除的节点下由自节点,那么这些子节点也会被完全删除,不会进行比较,这也是算法复杂度降低的原因之一。
可以看出,React在进行Diff算法比较时,只会对树进行简单的逐层节点比较。当发现某个节点类型不同时会直接进行简单的节点删除、节点新增的功能。当然,这也并没有导致严重的性能问题。
节点类型相同
第二种节点的比较是相同类型的节点,算法就相对简单而容易理解。React 会对属性进行重设从而实现节点的转换。虚拟 DOM 的 style 属性稍有不同,其值并不是一个简单字符串而必须为一个对象,因此直接进行对象的删增。
列表节点比较
列表节点的操作通常包括添加、删除和排序。当数量过大则会出现性能的问题,如果每个节点都没有唯一的标识,React 无法识别每一个节点,那么更新过程会很低效。
点击这个链接可以看看Diff节点的变化与生命周期的关系
在shape5转换为shape6时发现如果有标识(key)的优化引导则大大减少生命周期函数调用及DOM树变化:
加入Key前:B will unmount.
C will unmount.
C is created.
B is created.
C did mount.
B did mount.
A is updated.
R is updated.
加入Key后:C is updated.
B is updated.
A is updated.
R is updated.
这也为我对React的优化有了方向。