深刻理解React(二) —— 数据流和事件原理

版权声明:本文由左明原创文章,转载请注明出处: 
文章原文连接:https://www.qcloud.com/community/article/158前端

来源:腾云阁 https://www.qcloud.com/communitynode

 


这个,叫作竹笕,是中日传统禅文化中常见的庭院装饰品,它的构造可简单可复杂,但原理很简单,好比这个竹笕,水从竹笕顶部入口流入内部,并按照固定的顺序从上向下依次流入各个小竹筒,而后驱动水轮转动。对于强迫症患者来讲,观赏竹笕的绝对是一种很享受的过程的最爱,你会发现这些小玩意居然能这么流畅的协调起来,好神奇。
react

若是竹笕是一个组件的话,那么水就是组件的数据流。git

在React中,数据流是自上而下单向的从父节点传递到子节点,因此组件是简单且容易把握的,他们只须要从父节点提供的props中获取数据并渲染便可。若是顶层组件的某个prop改变了,React会递归地向下遍历整棵组件数,从新渲染全部使用这个属性的组件。

程序员

这个是前面看到的 KM 热点问题组件,拥有一个叫作 articles 的属性。github

在组件内部,能够经过this.props来访问props,props是组件惟一的数据来源,对于组件来讲:web

props永远是只读的。mongodb

不要尝试在组件内部调用setProps方法来修改props,若是你不当心这么作了,React会报错并给出很是详细的错误提示。数据库

组件的属性类型若是不进行声明和验证,那么极可能使用者传给你的属性值或者类型是无效的,那会致使一些意料以外的故障。好在React已经为咱们提供了一套很是简单好用的属性校验机制——
express

React有一个PropTypes属性校验工具,通过简单的配置便可。当使用者传入的参数不知足校验规则时,React会给出很是详细的警告,定位问题不要太容易。

PropTypes包含的校验类型包括基本类型、数组、对象、实例、枚举——


以及对象类型的深刻验证等等。若是内置的验证类型不知足需求,还能够经过自定义规则来验证。
若是某个属性是必须的,在类型后面加上 isRequired 就能够了。

React的一大创新,就是把每个组件都当作是一个状态机,组件内部经过state来维护组件状态的变化,这也是state惟一的做用。

state通常和事件一块儿使用,咱们先看state,而后看看state和事件怎样结合。
这是一个简单的开关组件,开关状态会以文字的形式表如今按钮的文本上。
首先看render方法,返回了一个button元素,给button注册了一个事件用来处理点击事件,在点击事件中对state的on字段取反,并执行 this.setState() 方法设置on字段的新值。一个开关组件就完成了。


组件渲染完成后,必须有UI事件的支持才能正常工做。

React经过将事件处理器绑定到组件上来处理事件。
React事件本质上和原生JS同样,鼠标事件用来处理点击操做,表单事件用于表单元素变化等,Rreact事件的命名、行为和原生JS差很少,不同的地方是React事件名区分大小写。
好比这段代码中,Article组件的section节点注册了一个onClick事件,点击后弹出alert。
有时候,事件的处理器须要由组件的使用者来提供,这时能够经过props将事件处理器传进来。

这个是刚才那个Article组件的使用者,它提供给Article组件的props中包含了一个onClick属性,这个onClick指向这个组件自身的一个事件处理器,这样就实现了在组件外部处理事件回调。

这是一个React组件实现组件可交互所需的流程,render()输出虚拟DOM,虚拟DOM转为DOM,再在DOM上注册事件,事件触发setState()修改数据,在每次调用setState方法时,React会自动执行render方法来更新虚拟DOM,若是组件已经被渲染,那么还会更新到DOM中去。

这些是React目前支持的事件列表。

React的组件拥有一套清晰完整并且很是容易理解的生命周期机制,大致能够分为三个过程:初始化、更新和销毁,在组件生命周期中,随着组件的props或者state发生改变,它的虚拟DOM和DOM表现也将有相应的变化。

首先是初始化过程,这里会着重讲,须要充分理解。
组件类在声明时,会先调用 getDefaultProps() 方法来获取默认props值,这个方法会且只会在声明组件类时调用一次,这一点须要注意,它返回的默认props由全部实例共享。
在组件被实例化以前,会先调用一次实例方法 getInitialState() 方法,用于获取这个组件的初始state。
实例化以后就是渲染,componentWillMount方法会在生成虚拟DOM以前被调用,你能够在这里对组件的渲染作一些准备工做,好比计算目标容器尺寸而后修改组件自身的尺寸以适应目标容器等等。
接下来就是渲染工做,在这里你会建立一个虚拟DOM用来表示组件的结构。对于一个组件来讲,render 是惟一一个必须的方法。render方法须要知足这几点:
1.只能经过 this.props 或 this.state 访问数据
2.只能出现一个顶级组件
3.能够返回 null、false 或任何 React 组件
4.不能对 props、state 或 DOM 进行修改
须要注意的是,render 方法返回的是虚拟DOM。

渲染完成之后,咱们可能须要对DOM作一些操做,好比截屏、上报日志、或者初始化iScroll等第三方非React插件,能够在 componentDidMount() 方法中作这些事情。固然,你也能够在这个方法里经过 this.getDOMNode() 方法取得最终生成DOM节点,而后对DOM节点作爱作的事情,但须要注意作好安全措施,不要缓存已经生成的DOM节点,由于这些DOM节点随时可能被替换掉,因此应该在每次用的时候去读取。

组件被初始化完成后,它的状态会随着用户的操做、时间的推移、数据更新而产生变化,变化的过程是组件声明周期的另外一部分 ——

更新过程。

当组件已经被实例化后,使用者调用 setProps() 方法修改组件的数据时,组件的 componentWillReceiveProps() 方法会被调用,在这里,你能够对外部传入的数据进行一些预处理,好比从props中读取数据写入state。

默认状况下,使用者调用组件的 setProps() 方法后,React会遍历这个组件的全部子组件,进行“灌水”,将props从上到下一层一层传下去,并逐个执行更新操做,虽然React内部已经进行过不少的优化,这个过程并不会花费多少时间,可是程序员里永远不缺少长期性能饥渴的同窗,不用担忧,React有一个可以解决你性能饥渴的办法——shouldComponentUpdate()。
有时候,props发生了变化,但组件和子组件并不会由于这个props的变化而发生变化,打个比方,你有一个表单组件,你想要修改表单的name,同时你可以确信这个name不会对组件的渲染产生任何影响,那么你能够直接在这个方法里return false来终止后续行为。这样就可以避免无效的虚拟DOM对比了,对性能会有明显提高。
若是这个时候有同窗仍然饥渴难耐,那么你能够尝试 不可变数据结构(用过mongodb的同窗应该懂)。
组件在更新前,React会执行componentWillUpdate() 方法,这个方法相似于前面看到的 componentWillMount()方法,惟一不一样的地方只是这个方法在执行的时候组件是已经渲染过的。须要注意的是,不能够在这个方法中修改props或state,若是要修改,应当在 componentWillReceiveProps() 中修改。
而后是渲染,React会拿此次返回的虚拟DOM和缓存中的虚拟DOM进行对比,找出【最小修改点】,而后替换。
更新完成后,React会调用组件的componentDidUpdate 方法,这个方法相似于前面 componentDidMount 方法,你仍然能够在这里能够经过 this.getDOMNode() 方法取得最终的DOM节点。

香港电影结尾常常看到一个剧情,就是英雄战胜了坏人,而后警察出来擦屁股——

警察偶尔还能立功,而 componentWillUnmount 最可怜,他除了擦屁股什么也作不了。
你能够在这个方法中销毁非React组件注册的事件、插入的节点,或者一些定时器之类。这个过程可能容易出错,好比绑定了事件却没销毁,这个React可帮不了你,你本身约的炮,含着泪也要打完。


两节内容讲了上手React所必备的知识。
后面讲价值。

直出有多快我就很少说了。
由于有虚拟DOM的存在,React能够很容易的将虚拟DOM转换为字符串,这便使咱们能够只写一份UI代码,同时运行在node里和和浏览器里。

在node里将组件HTML渲染为一段HTML一句话便可。
不过围绕这个renderToString咱们还要作一些准备工做。代码有点多,你们作好心理准备。

这是一个express的路由方法,在这里:
1.从后台server或数据库等来源拉取数据
2.引入要渲染的React组件
3.调用React.renderToString()方法来生成HTML
4.最后发送HTML和数据给浏览器

这里为了方便描述,没有写拉取数据的代码,你们自行脑补。

须要注意的是这里的JSON字符串中可能出现结尾标签或HTML注释,可能会致使语法错误,这里须要进行转义。

页面的示例代码原本打算用你们更熟悉的HTML,但发现代码量太多了PPT里一页放不下,因此换成了jade代码,没用过jade的同窗也顺便了解一下,我也顺便给jade打个广告。
这个页面作了X个事:
1.将前面在action里生成的HTML写到#container元素里
2.引入必须的JS文件
3.获取action提供的数据
4.渲染组件

这就是React的服务端渲染,组件的代码先后端均可以复用。
<有没有没理解清楚的同窗?>

是否是感受React挺牛逼的?你们觉得React就这么点能耐吗?

React可以用一套代码同时运行在浏览器和node里,并且可以以原生App的姿式运行在iOS和Android系统中,即拥有了web迭代迅速的特性,又拥有原生App的体验。
这个姿式叫作 React-Native。
这是React和React-Native在github上的数据,能够看出React-Native也是至关热门——由于React-Native可以使React的价值最大化,这个价值是什么呢——对业务来讲,意味着不须要为了作终端版本就招聘和前端等量人力的终端开发,同时意味着咱们成为全栈工程师有了一个捷径。

了解iOS开发的同窗都知道,水果公司对应用上架的审核效率实在让人无力吐槽,不少团队上一个版本还没审核结束,下一个版本就已经作好了。而React-Native支持从网络拉取JS,这样iOS应用也可以像web同样实现快速迭代了。

这个是react-native的调试过程

做为一个没写过一句Object-C代码的web前端开发,我只用了一天时间就上手了react-native,而后用了半天时间作出了一个简单的demo页面,能够看到react-native的生产效率仍是很是高的。

单元测试顾名思义,是对各个模块进行最小范围的测试,容易。
咱们来演示一个checkbox的单元测试过程。

看代码

由于虚拟DOM的存在,使得react的代码很容易作好单元测试,这是上面那段代码的测试用例,经过karma执行后便可看到结果。

因此你可能须要这些东西


课后练习

(若是你已经看到这里了,为什么再也不花1分钟思考一下上面3个问题)

上一期React技术文章:

深刻理解 React (一) - JSX和虚拟DOM

相关文章
相关标签/搜索