React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

ReactJS官网地址:http://facebook.github.io/react/

Github地址:https://github.com/facebook/react

React认为一个组件应该具有如下特征:

(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;

(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景;

(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;

我们新建一个html文件,引用react.js和JSXTransformer.js这两个js文件。html模板如下(js路径改成自己的):

<!DOCTYPEhtml><html><head><scriptsrc="../build/react.js"></script><scriptsrc="../build/react-dom.js"></script><scriptsrc="../build/browser.min.js"></script></head><body><divid="example"></div><scripttype="text/babel">//**Ourcodegoeshere!**</script></body></html>

script的type是text/babel,这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。

其次,上面代码一共用了三个库:react.js、react-dom.js和Browser.js,它们必须首先加载。其中,react.js是 React 的核心库,react-dom.js是提供与 DOM 相关的功能,Browser.js的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。

下面开始看react该怎么写,还是传统的老规矩 hello word:

<!DOCTYPEhtml><html><head><scriptsrc="../build/react.js"></script><scriptsrc="../build/react-dom.js"></script><scriptsrc="../build/browser.min.js"></script></head><body><divid="example"></div><scripttype="text/babel">ReactDOM.render(<h2>helloword</h2>,document.getElementById('example'));</script></body></html>

在上例的body中,有一个div,id是example, 然后由react的渲染器把h2标签渲染到该div中。

ReactDOM.render(DOM节点,被插入的父节点);

这一句代码是最常用也是非常必要的一句。 这句中有个很重要的地方就是html语法和js语法的混写,这是jsx语法的特点,在jsx语法里,遇到 尖括号就按照html来解析,遇到花括号就按照js语法去解析。下面这个例子更能说明jsx语法的写法:

varlist=["word","man","boy"];ReactDOM.render(<div>{list.map(function(name){return<div>hello{name}</div>})}</div>,document.getElementById('example'));</script>

最终的结果是:

helloword

helloman

helloboy


这里有一点需要说明的是 ReactDOM.render 渲染器的第一个参数里,有且只能有一个顶级节点,不能有多个并列,否则会报错。JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员。

varlist=[<h2>word</h2>,<h2>man</h2>,<h2>boy</h2>];ReactDOM.render(<div>{list}</div>,document.getElementById('example'));</script>

最终结果是:

wordmanboy

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类:

varHelloWord=React.createClass({render:function(){return<p>hello{this.props.name}</p>}});ReactDOM.render(<HelloWordname="喵星人"/>,document.getElementById('example'));

最终结果是:

hello喵星人


上例中用React.createClass创建了一个组件类HelloWord,这里有一点需要注意:组件类名字的首字母必须是大写的,否则会报错。React.createClass接收一个对象,对象中必须有render属性,render属性的值一般都是写成一个函数,然后返回一个DOM对象,别忘了上面说的,这个DOM对象有且只能有一个顶级节点,否则会报错。

我们在上面的代码的return 里会看到有这么一段:this.props.name,然后在ReactDom.render中的第一个参数里会看到标签有一个属性name="喵星人",这里需要记住的一点是name="喵星人"看上去就像在对函数传参数,而this.props.name就是对参数的接收。

添加组件属性,有一个地方需要注意,就是class属性需要写成className,for属性需要写成htmlFor,这是因为class和for是 JavaScript 的保留字。


this.props对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children属性。它表示组件的所有子节点。

varNotesList=React.createClass({render:function(){return(<ol>{this.props.children.map(function(child){return<li>{child}</li>;})}</ol>);}});ReactDOM.render(<NotesList><span>hello</span><span>world</span><p>main</p></NotesList>,document.getElementById('example'));

最终运行结果:

hello

world


3. main



2 和3之间的换行是因为p标签会自带一个换行,li标签也会有一个换行,所以中间就有了一个空白行.


组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI

varLikeButton=React.createClass({getInitialState:function(){return{liked:false};},handleClick:function(event){this.setState({liked:!this.state.liked});},render:function(){vartext=this.state.liked?'like':'haven\'tliked';return(<ponClick={this.handleClick}>You{text}this.Clicktotoggle.</p>);}});ReactDOM.render(<LikeButton/>,document.getElementById('example'));

最终结果:

Youhaven't likedthis. Click to toggle.

当在文字上点击时会变成:

Youlikethis. Click to toggle.

然后一直点击就会在两句英文之间来回切换。

这里需要注意的是 getInitialState 是React默认的属性,需要返回一个对象,可以是NULL或者其他,表示初始状态,返回的对象中可以不止有一个属性,修改这些状态可以使用react提供的方法this.setState(对象), 这里的对象可以只修改初始状态中的某一个属性,也可以同时修改多个。当任何一个状态改变的时候react就会重新调用 render属性所指向的函数,也就意味着会重新渲染该组件。


组件的生命周期分成三个状态:

Mounting:已插入真实 DOM

Updating:正在被重新渲染

Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will函数在进入状态之前调用,did函数在进入状态之后调用,三种状态共计五种处理函数。

componentWillMount()

componentDidMount()

componentWillUpdate(object nextProps, object nextState)

componentDidUpdate(object prevProps, object prevState)

componentWillUnmount()

此外,React 还提供两种特殊状态的处理函数。

componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用

shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

varHello=React.createClass({getInitialState:function(){return{opacity:1.0};},componentDidMount:function(){this.timer=setInterval(function(){varopacity=this.state.opacity;opacity-=.05;if(opacity<0.1){opacity=1.0;}this.setState({opacity:opacity});}.bind(this),100);},render:function(){return(<divstyle={{opacity:this.state.opacity}}>Hello{this.props.name}</div>);}});ReactDOM.render(<Helloname="world"/>,document.body);

上面代码在hello组件加载以后,通过componentDidMount方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。这里需要注意的地方是在setInterval的第一个参数也就是计时器触发函数后使用了bind(this),计时器函数中不能直接使用this来获取react的状态或属性,需要绑定this。

小结:

react提供的属性:

getInitialState 设置默认状态

setState 修改状态

render 返回组件

componentWillMount() 插入真实DOM之前调用

componentDidMount() 插入真实DOM之后调用

componentWillUpdate(object nextProps, object nextState) 重新渲染之前调用

componentDidUpdate(object prevProps, object prevState) 重新渲染之后调用

componentWillUnmount() 移出真实DOM之前调用

propTypes 验证组件实例的属性是否符合要求

getDefaultProps 设置组件属性的默认值。

最后两个属性本文中没有介绍,详细介绍请参阅http://www.ruanyifeng.com/blog/2015/03/react.html