关于React
React最近很火。一来一直以来DOM操作都是性能瓶颈,二来从另一个角度来诠释模块化。虽然说它按传统MVC的概念来分的话智仅仅能算V层面,同AngularJS这类MVVM框架在广度有较大距离。但是呢,一件事物不能一味求大求全,何况并不是一味大就可以解决EveryThing————比如YUI。
React之所以成功,我以为,它是击中了前端从业人员的痛点:
- 多个文章和书籍都无数次在说,DOM是性能后腿。然而避无可避。
- 模块化说来容易做起来永远是一项业界痛点。太多代码写了一年又一年,也许下一年还会重复写。
React根据这两个痛点做了两件事:
- shadow DOM ==> 减少不必要的DOM操作
- JSX ==> 将模块相关的HTML,CSS,JS放到一起,这也许是一项前端领域的“逆生长”。
——本文只说JSX
JSX
JSX有什么好处呢:
- 允许使用熟悉的语法来定义HTML元素树
- 提供更加语义化且易懂的标签
- 程序结构更加直观
- 抽象了React.Element的创建过程
- 随时掌控HTML标签以及生成这些标签的代码
- 原生的Javascript
当然,上面说了那么多只是文科考试一般的答案,实际工作中,没人会背诵下来。实际上,JSX仅仅是发明出来方便将html,css,js杂糅到一起做成模块用的工具,用不用可以看喜好。简单来对比下用和不用的区别(当然,用不用JSX,React依然是React):
1 | //不使用JSX |
两者在最后运行时候是等效的,但是很显然,JSX抹平了HTML在js中的转换问题,做到了将html标签转换js可识别的DOM对象的自动化——大家都干过用N个”+”来拼接HTML字符串并innerHTML到dom元素中的活儿,一旦字符串庞大,这个拼接就会很费神,然而这仅仅是字符串,手动来操作一个复杂的html字符串转换js认识的DOM,这将会更加复杂。所幸JSX为我们做好了这项工作。
step1
首先让我们先来个Hello World!第一步就老实从Hello组件做起好了。来个半官方的demo,我仅仅改了标签而已。注意这里JSX浏览器端编译工具体积达到1.3M,这里再次说明了,这个转换是一件相当复杂的事情。
step2
hello world到此为止就可以运行了,但是这个demo仅仅是一个写死的,不可以复用的html——事实上复制粘贴比它快多了,对吧?
第二步,来构建一个简单的组件。这里我抄个demo过来,就不写了。
组件的层级: - CommentBox - CommentList - Comment - CommentForm
代码如下:
这里定义一个评论组件,他包含一个评论列表和一个提交评论的表单,我们用React.createClass分别构造了这三个小模块,然后在CommentBox中引用了CommentList和CommentForm,这样,一个包含列表和表单的评论组件就做好了——当然,它只是随便填充了点文字意思了那么一下。。。
step3
到此为止,这个组件可以实现复用了,但是,它的数据还是写死的。CommentList里面也没有Comment,完善一下:
JS Bin on jsbin.com
说一下这里有哪些需要注意的,它做了什么
- 添加了一个Comment组件,并改变了CommentList
- 传入了data对象
- 在CommentList中根据传入的data遍历输出了Comment
写在step4之前
写到step3,步子跨越的有些大了。这里补充一下关于JSX的一些基础,和语法相关常识。
JSX的注释
JSX本质上是js,即使当它是JSX时候可以不太遵循JS语法,但是一旦编译成JS,它就必须遵循JS的语法。
这里简单说一下常见的两种情况:
注释在JS中
注释在HTML中
注释在JS中
注释在JS中其实没有太多好说的,和常规的JS一样
注释在HTML中
注释在HTML中的话,有两种情况:
- 作为子节点
- 作为内联属性
1 | //作为子节点 |
这里的注释,可以使用 “//“&”/* */“
JSX模板替代性相关
模板的作用众所周知,它至少起到以下作用:
- 在标记中输出变量
- 选择性输出HTML
- 遍历输出固定HTML标记
- 分支支持(if else之流)
这里就根据上面4个,一一说到JSX中的替代解决方案
在标记中输出变量 –> {}
在JSX中,花括号{}中间的内容会被渲染为动态值,在{}中放入的任何东西都会被求值,实际上每个{}之间,都会放入一个context(上下文)。
1 | //解析变量 |
选择性输出HTML –> dangerouslySetInnerHTML
1 | ... |
遍历输出固定HTML标记 –> this.props.data.map
关于遍历输出固定html标记,在上文的例子中有一个已经运行起来的demo,把它提取出来:
1 | var CommentList = React.createClass({ |
大致说一下这里出现的各种变量:
首先要说的是 {this.props.children} ,这是一个非常关键的变量。它指向哪个变量呢?
1 | //在CommentList中调用 |
对比上面两个code片段,可以看到:{this.props.children}的地方,出现了”测试变量”。
——{this.props.children}实际上就是指向了Comment标记开始到结尾过程中的子元素
这里解释了JSX中如何生成遍历过程中输出不同变量的,但是还没有说明如何进行遍历过程,这里就是this.props.data.map的作用了。熟悉JS的话就不需要再解释了,map对数组每个元素操作后返回了新的变量组成的数据,最后放到{}中去解析去了:数组是会被当做字符串加起来innerHTML到目标位置的。
最后整理下实现的路径:
- 定义Comment组件,把Comment标记中的文本作为变量放到内容区,以备遍历过程中输出不同变量之需
- 使用map方法生成一个包含多个Comment组件的数组,把逻辑放到CommentList定义语句中
- 将返回的数组放到{}中去解析生成,从而遍历生成子节点
分支支持(if else之流)
分支这个最后决定一笔略过了——前面说过了,{}中会有个context,所以,if/else在js中怎么用,这里就可以怎么用。
总结
JSX应该算是是React的语法糖,它是React的语法更加简洁,好写和好认。用好JSX是React实现实用意义的第一步。
本文简单解释了必要的概念,从step1到step4,实现了一个非常简单评论组件——虽然它很简单,但是一旦封装好却可以重复使用。
在step1到step4,实践了复用子组件的同时,实现了模板在实用意义中至关重要的3点:
- 在标记中输出变量
- 选择性输出HTML
- 分支支持(if else之流)
本文将就此终止,但是本文仍不完善,比如没有讲到this.props,但是这部重要,最重要的是,如何把JSX当成模板用一回,是将JSX作为实用工具最初的一步。关于this.props和组件中数据传递,下一篇再说。
this end