reactjs 是什么?
reactjs是来自facebook公司的用于构建用户界面的JavaScript库。
GitHub地址:https://github.com/facebook/react
reactjs的两个衍生项目也值得注意。
- react-native:用reactjs写手机app
GitHub地址:https://github.com/facebook/react-native
- react-canvas:用canvas代替臃肿缓慢的DOM作为UI,在移动端获得能与原生应用媲美的流畅效果 GitHub地址:https://github.com/Flipboard/react-canvas
reactjs 真的将html/xml和js代码混杂在一起吗?
reactjs的jsx语法,让许多人感觉仿佛回到了原始社会。这么多年努力地让html\css\javascript三者分离,好不容易走到今天,reactjs却走回老路,让人难以接受。我也几次三番因为jsx而放弃了解reactjs。
目前体验下来,发觉那是误解。
reactjs比其他前端模板引擎更彻底的分离html与javascript。前端模板引擎,绝大多数基于html字符串;而reactjs不是。能接受前端模板引擎的人,也能接受jsx。
jsx的实质是:用xml的语法写函数调用。它没有拼接html字符串,也不要求一定要使用jsx,手写函数调用,也是可以的。
在原生DOM中,用js构造dom的方式是这样的:
1 | //要构造的dom: |
如你所见,它颇为繁琐,我们可以封装一下:
1 | //第一个参数为node名 |
如上,从html语法到js构造dom,再到React.createElement的封装。
现在有个编译工具,可以让你用html语法来写React.createElement,部署上线前编译回来。你愿意吗?
不管你的答案是什么,但这就是jsx的一半真相。
正是由于jsx不是html字符串,所以有如下特点:
- html的class与for属性在js里是保留字,所以jsx里要用别名className与htmlFor
- 不能像下面那样操作html的checked属性
1 | //在其他前端模板引擎中,可以这么做,因为是拼接字符串 |
- 不能直接写并列的元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33//这样写是错误的
var MyComponent = React.createClass({
render: function() {
return <div>first div</div><div>second div</div>
}
})
//因为编译后,return 两个函数调用,就算不报错,也只调用第一个函数,不合意图
var MyComponent = React.createClass({
render: function() {
return React.createElement('div', null, 'first div') React.createElement('div', null, 'second div')
}
})
//所以有时难免要增加dom层级
var MyComponent = React.createClass({
render: function() {
return (
<div>
<div>first div</div>
<div>second div</div>
</div>
)
}
})
//编译后,合乎语法和编程意图了
var MyComponent = React.createClass({
render: function() {
return React.createElement('div', null,
React.createElement('div', null, 'first div'),
React.createElement('div', null, 'second div'))
}
}) - jsx要求标签一定要闭合,html5中不强制要求闭合的,在jsx也都要闭合,以便识别
- 封装的组件要用大写字母开头,以便跟html标签区分。reactjs与web component
1
2
3
4//不合规则
<tap />
//合乎规则
<Tap />
web component是下一代的前端标准,提供了shadow dom、templete元素、Imports与自定义元素的功能。其中自定义元素提供了生命周期回调函数:
- createdCallback: 创建时调用
- attachedCallback: 添加到dom树时调用
- detachedCallback: 从dom树衣橱时调用
- attributeChangedCallback:属性改变时调用
在reactjs中也有相似但更丰富的生命周期方法:
- componentWillMount: 初始化渲染前调用
- componentDidMount: 初始化渲染后调用
- componentWillReceiveProps: 接受新props时调用
- shouldComponentUpdate:接受新props或state时调用,返回值true/false决定是否更新视图
- componentWillUpdate: 在接收到新的 props 或者 state 之前立刻调用。在初始化渲染的时候该方法不会被调用
- componentDidUpdate:在组件的更新已经同步到 DOM 中之后立刻被调用
- componentWillUnmount: 在组件从 DOM 中移除的时候立刻被调用
reactjs与web component的关系,在我个人看来:reactjs是纯js实现的一种component标准,它可以与DOM无关,甚至与Web无关。
在reactjs中注册组件像这样:
1 | //reactjs跟objective-c在方法命名上有些相似,使劲儿用全称,与传统js编程的缩写习惯相悖 |
总的来说,reactjs允许我们用React.createClass来拓展React.createElement的参数范畴。
- 默认情况下,它接受原生html标签,所以web Component普及后,reactjs也不会被淘汰,无非是多了一些html标签罢了
- React.createClass方法,可以提供新的html标签给React.createElement,创造了封装复杂dom结构、组件化的空间
reactjs 的虚拟dom
之前说了jsx的一半真相,另一半是,React.createElement并没有直接了当的用js构造dom,它构造了一种数据结构。
使用reactjs时,表面上我们在操作dom,其实是操作数据,reactjs通过自己的dom diff算法,对比前后的数据,找到diff差异点,按最小粒度更新视图。
正因如此,reactjs的UI层才是可替换的,构造另一套从数据到视图的映射逻辑,就能应用在canvas乃至手机原生UI上。
reactjs 的单向数据流
reactjs组件内部的this.props对象,是组件实例的父级组件提供的,提供方式就像写html属性一样。
如此,父级复父级,数据可以从最顶层的组件实例,层层传递到最底层的组件中去,然而反过来却不行,这就是单向数据流的意思。
1 | //最底层的todo |
结语
reactjs是有趣且富有生命力与表现力的javascript库,有其适用的场景,也有许多需要注意的事项与容易踩到的坑。
总体而言,学会它不会让人后悔(想想那些学angular1的同学吧)。
在此,可以去TodoMVC 下载react制作的mvc项目来参考学习React-TodoMVC