
由于 react 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 web 开发的主流工具。
既然 react 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 react 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 react 本身还在不断变动,api 一直在调整,至今没发布1.0版。
下面要讲解的12个例子在各个 <code>demo</code> 子目录,每个目录都有一个 <code>index.html</code> 文件,在浏览器打开这个文件(大多数情况下双击即可),就能立刻看到效果。
使用 react 的网页源码,结构大致如下。
上面代码有两个地方需要注意。首先,最后一个 <code><script></code> 标签的 <code>type</code> 属性为 <code>text/babel</code> 。这是因为 react 独有的 jsx 语法,跟 javascript 不兼容。凡是使用 jsx 的地方,都要加上 <code>type="text/babel"</code> 。
其次,上面代码一共用了三个库: <code>react.js</code> 、<code>react-dom.js</code> 和 <code>browser.js</code> ,它们必须首先加载。其中,<code>react.js</code> 是 react 的核心库,<code>react-dom.js</code> 是提供与 dom 相关的功能,<code>browser.js</code> 的作用是将 jsx 语法转为 javascript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。
上面命令可以将 <code>src</code> 子目录的 <code>js</code> 文件进行语法转换,转码后的文件全部放在 <code>build</code> 子目录。
reactdom.render 是 react 的最基本方法,用于将模板转为 html 语言,并插入指定的 dom 节点。
上面代码体现了 jsx 的基本语法规则:遇到 html 标签(以 <code><</code> 开头),就用 html 规则解析;遇到代码块(以 <code>{</code> 开头),就用 javascript 规则解析。上面代码的运行结果如下。
上面代码的<code>arr</code>变量是一个数组,结果 jsx 会把它的所有成员,添加到模板,运行结果如下。
上面代码中,变量 <code>hellomessage</code> 就是一个组件类。模板插入 <code><hellomessage /></code> 时,会自动生成 <code>hellomessage</code> 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 <code>render</code> 方法,用于输出组件。
注意,组件类的第一个字母必须大写,否则会报错,比如<code>hellomessage</code>不能写成<code>hellomessage</code>。另外,组件类只能包含一个顶层标签,否则也会报错。
上面代码会报错,因为<code>hellomessage</code>组件包含了两个顶层标签:<code>h1</code>和<code>p</code>。
组件的用法与原生的 html 标签完全一致,可以任意加入属性,比如 <code><hellomessage name="john"></code> ,就是<code>hellomessage</code> 组件加入一个 <code>name</code> 属性,值为 <code>john</code>。组件的属性可以在组件类的 <code>this.props</code> 对象上获取,比如 <code>name</code> 属性就可以通过 <code>this.props.name</code> 读取。上面代码的运行结果如下。
添加组件属性,有一个地方需要注意,就是 <code>class</code> 属性需要写成 <code>classname</code> ,<code>for</code> 属性需要写成 <code>htmlfor</code> ,这是因为 <code>class</code> 和 <code>for</code> 是 javascript 的保留字。
上面代码的 <code>notelist</code> 组件有两个 <code>span</code> 子节点,它们都可以通过 <code>this.props.children</code> 读取,运行结果如下。
这里需要注意, <code>this.props.children</code> 的值有三种可能:如果当前组件没有子节点,它就是 <code>undefined</code> ;如果有一个子节点,数据类型是 <code>object</code> ;如果有多个子节点,数据类型就是 <code>array</code> 。所以,处理 <code>this.props.children</code> 的时候要小心。
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
上面的<code>mytitle</code>组件有一个<code>title</code>属性。<code>proptypes</code> 告诉 react,这个 <code>title</code> 属性是必须的,而且它的值必须是字符串。现在,我们设置 <code>title</code> 属性的值是一个数值。
这样一来,<code>title</code>属性就通不过验证了。控制台会显示一行错误信息。
此外,<code>getdefaultprops</code> 方法可以用来设置组件属性的默认值。
上面代码会输出"hello world"。
上面代码中,组件 <code>mycomponent</code> 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 dom 节点,虚拟 dom 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 <code>ref</code> 属性,然后 <code>this.refs.[refname]</code> 就会返回这个真实的 dom 节点。
需要注意的是,由于 <code>this.refs.[refname]</code> 属性获取的是真实 dom ,所以必须等到虚拟 dom 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 <code>click</code> 事件的回调函数,确保了只有等到真实 dom 发生 <code>click</code> 事件之后,才会读取 <code>this.refs.[refname]</code> 属性。
上面代码是一个 <code>likebutton</code> 组件,它的 <code>getinitialstate</code> 方法用于定义初始状态,也就是一个对象,这个对象可以通过 <code>this.state</code> 属性读取。当用户点击组件,导致状态变化,<code>this.setstate</code> 方法就修改状态值,每次修改以后,自动调用 <code>this.render</code> 方法,再次渲染组件。
由于 <code>this.props</code> 和 <code>this.state</code> 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,<code>this.props</code> 表示那些一旦定义,就不再改变的特性,而 <code>this.state</code> 是会随着用户互动而产生变化的特性。
mounting:已插入真实 dom updating:正在被重新渲染 unmounting:已移出真实 dom
react 为每个状态都提供了两种处理函数,<code>will</code> 函数在进入状态之前调用,<code>did</code> 函数在进入状态之后调用,三种状态共计五种处理函数。
componentwillmount() componentdidmount() componentwillupdate(object nextprops, object nextstate) componentdidupdate(object prevprops, object prevstate) componentwillunmount()
此外,react 还提供两种特殊状态的处理函数。
componentwillreceiveprops(object nextprops):已加载组件收到新的参数时调用 shouldcomponentupdate(object nextprops, object nextstate):组件判断是否重新渲染时调用
上面代码在<code>hello</code>组件加载以后,通过 <code>componentdidmount</code> 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。
另外,组件的<code>style</code>属性的设置方式也值得注意,不能写成
而要写成
上面代码使用 jquery 完成 ajax 请求,这是为了便于说明。react 本身没有任何依赖,完全可以不用jquery,而使用其他库。
上面代码从github的api抓取数据,然后将promise对象作为属性,传给<code>repolist</code>组件。
如果promise对象正在抓取数据(pending状态),组件显示"正在加载";如果promise对象报错(rejected状态),组件显示报错信息;如果promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。
<a href="http://facebook.github.io/react" target="_blank">react's official site</a>
<a href="https://github.com/facebook/react/tree/master/examples" target="_blank">react's official examples</a>
(完)