由于工做须要,这段时间一直在看React相关的东西,不得不感叹Facebook在开源项目和软件架构方面的实力,其在React中提出的一些设计思想很是新颖,极大的简化了前端开发的代码逻辑。本文将介绍React相关的基础知识,以及本人在学习过程发现的好的学习资料。javascript
React是Facebook开源的一套用来建立用户界面的JS库,它重在界面渲染,所以不少人认为React是传统MVC中的V(视图),使用React你能够轻松构建可交互、基于状态的、可复用的UI组件。html
Facebook建立React的初衷是想使得构建随着时间流逝数据不断变化的大规模应用程序变得简单,Facebook工程师认为传统的MVC模式已经不适用于构建这种大规模应用,由于当系统中的模型和对应的视图愈来愈多时,其复杂程度就会迅速扩大,加之可能存在的双向数据流动,致使程序难以理解和调试。前端
React有两个主要思想:java
简单
仅仅表达出你的应用在任意时间点应该呈现的样子(这种展示是能够预测的,给编写测试代码带来了极大的便利),数据驱动UI,当底层数据变了,React会自动处理全部用户界面的更新,经过Dom Diff算法尽量少的减小Dom变化以提升性能。react
声明式
当数据(状态)变化时,React内部知道该怎样去局部更新须要变化的部分视图。也就是说在在编程时咱们只须要告诉React想要的是什么,而不须要告诉React怎么样一步步Dom操做才能到达须要的效果。能够参见这里关于声明式和命令式编程的区别。webpack
选择React无非是看中了它所表现出的突出优势:ios
组件化思想,使应用更加容易维护和复用git
Virtual Dom使得React不只能够在浏览器端渲染也能够运行在服务端,这为编写同构应用提供了可能es6
Dom Diff算法尽量的减小Dom操做,提升应用的性能github
单向数据流使应用逻辑可容易理解,基于状态的视图更新使应用状态可预测,便于测试
固然React也不是完美的,它的JSX语法虽然提供了强大的功能,但它却将HTML结构分散进了JS文件中,不利于初学者对网页总体结构的把握,同时Css-in-js的写法也背离了Web标准倡导的表现结构逻辑分离的思想。如何取舍还要看实际状况。
想要快速开始学习React,官方tutorial是个不错的选择,上面包含了构建React组件的关键性内容。若是你想亲手敲两行代码体验一下,你能够下载一个starter kit,里面包含了相关依赖文件和一些实例,固然你也可使用jsfiddle在线体验。
JSX是React提供的用来快速建立React树节点的语法糖,它可以使用相似HTML的语法建立JavaScript对象,固然你也可使用提供的api手动建立。
例如咱们事先建立了一个Nav组件,那么在对应的Dom节点渲染它时就能够像下面同样:
var navElement = <Nav className='nav' />; //jsx语法,react会自动将其转换成javascript 对象 ReactDOM.render(navElement, /*真实dom节点*/); //渲染
JSX语法的一个重要特色是可以使用JavaScript表达式,经过在属性值或子组件混入js表达式,可以轻易的写出更加复杂的组件,js表达式须要用一对大括号{}包裹起来。
例如属性值混入js表达式:
//显示不一样的样式类 var person = <Person className={window.isLoggedIn ? 'logged' : null />; //输入框禁止输入 var input = <input type='button' disabled={false} />;
子组件混入js表达式:
//根据isLoggedIn的值嵌入不一样的子组件 var content = <Container> {window.isLoggedIn ? <Nav /> : <Login />}</Container>; //数组循环建立多个子组件,key属性不能省略,不然会报错 var results = [1, 2, 3, 4]; var list = <ol> {results.map(function(result, index) { return <li key={index}>{result}</li>; })} </ol>
JSX既能解析React组件标签也能解析HTML标签,可是React组件必须是首字母大写,如上面的Container;HTML标签则照常小写便可,如ol
style属性值必须是JavaScript对象
JSX最外层的标签必须是惟一的,若是有多个能够用div标签将其包裹起来
由于JSX自己是JavaScript,HTML一些与JavaScript关键字有冲突的属性,如class、for都要转换成相应的className、htmlFor,更多不一样参见jsx-gotchas
循环建立多个同类子组件的时候,要带上key属性,且key值是惟一的,如上例的多个li标签
React提倡组件化思想,认为一个应用应该是多个互相独立的组件构成的大组件,每一个组件只关心本身部分的逻辑。以下图的评论界面所示,一个评论组件CommentBoxComponent由CommentListComponent和FormBoxComponent组件组成,相应的CommentListComponent组件又由CommentItemComponent和ButtonComponent组成。
对于初学者而言,想要很好的对UI进行组件划分可能比较困难,可是遵循一些组件划分原则是有益的:
单一职责,一个组件应该只作一件事情,当你发如今一个组件作了太多事情的时候,应该考虑将其拆分为更小的子组件。
根据数据模型拆分组件,由于React是基于数据来渲染UI,因此让你的组件仅仅是用来表现数据模型的某个部分一般是正确的选择。
构建纯组件,一个纯组件一般没有内部状态(state,后面会讲到),它用来渲染的数据彻底来自于输入的props,使用相同的props来渲染相同的纯组件屡次将获得相同的UI,不存在内部状态致使渲染不一样。
React提供了createClass来建立组件,它接受一个对象做为参数,该对象包含一些属性和函数来具体描述一个组件,其中render函数是必须的,其余的状态初始化函数以及生命周期相关的函数都是可选的:
//注意Component首字母大写 var Component = React.createClass({ getIntialState: function(){}, //初始化组件状态 getDefaultProps: function(){}, //初始化组件的默认属性 propTypes: {}, //规定属性的存在性和类型 //一些生命周期相关函数 componentWillMount: function(){}, //组件被嵌入以前触发 componentDidMount: function(){}, //组件被嵌入以后触发 componentWillReceiveProps: function(){}, //当props有改变时触发 componentWillUnmount: function(){}, //组件被注销以前触发 //渲染函数,不能省略 render: function() { return <h1>Hello </h1> ; } });
以上是ES5的写法,若是你看了一些脚手架项目,你会发现有些使用了ES6的语法,ES6建立组件的语法有很大的不一样:
class Component extends React.Component { constructor() { super(); this.state = { //组件状态 }; } static defaultProps = { //组件属性 }; render() { return ( <div onClick={this.handleClick}> You {text} this. Click to toggle. </div> ); } }
咱们能够看到使用了ES6语法的组件构建很像在编写面向对象编程时建立类,更多写法的不一样,能够参见es5-es6写法对照表。
前面咱们有涉及props和state这个两个概念,这里作一下解释。
当咱们在使用定义好的组件时,能够向其添加一些属性,在组件定义的内部,能够经过this.props来访问这些属性,以下在render方法里渲染动态数据:
var Component = React.createClass({ getDefaultProps: function(){ return { name: 'world' } }, propTypes: { name: React.PropTypes.string //设置属性的类型 }, render: function(){ return ( <h1>Hello, {this.props.name}!</h1> //访问name属性 ); } }); ReactDOM.render(<Component name="Handsome" />, document.body);
其中getDefaultProps用来设置默认的属性值,propTypes来设置属性的类型,在使用时若是属性类型不匹配会提示。
this.props是只读的,它一般用来传递来自父组件的数据,也是React构建单向数据流的方式。
相同的组件之因此可以表现出不同的UI是由于它们内部拥有不一样的状态(states),每一个组件均可以拥有本身的state,而且能够在须要的时候经过props传递给子组件。组件能够经过setState函数来修改内部的状态,同时触发界面的渲染。
var ParentComponent = React.createClass({ getInitialState: function(){ return { name: 'Tyler McGinnis', friend: 'Tom' } }, handleClick: function(e){ this.setState({name: 'Tim'}); //更改状态 }, render: function(){ return ( <div> <h3> Name: {this.state.name} </h3> //点击触发事件,调用handleClick改变组件状态 <button onClick={this.hanleClick}>change name</button> <Component name={this.state.friend} /> //传递状态到子组件 </div> ) } });
这里须要注意的是getInitialState是用来初始化组件内部状态的默认值,不要在该方法里面使用this.props,除非某个属性有明确的语义是被用来初始化state的,详细请参看这里。
props是只读的,不可以在组件内部修改,它是父组件向子组件传递数据的途径;state是组件自身的状态,它不能是父组件传递过来的数据,而且state是能够改变的。
合理的状态操做是建立多个只负责渲染数据的无状态(stateless)组件,在它们的上层建立一个有状态(stateful)组件并把它的状态经过 props 传给子组件。这个有状态的组件封装了全部用户的交互逻辑,而这些无状态组件则负责声明式地渲染数据。
如前面组件建立里提到,组件建立时能够提供几个生命周期函数,这些函数决定了组件在不一样的时期进行的操做。
componentWillMount: 在初始化渲染执行前当即调用且仅调用一次。若是在这个方法内部调用setState并不会触发从新渲染,你能够将一些只须要执行一次的操做放在这个函数里。
componentDidMount:在初始化渲染以后,当即调用一次,这个时候你能够访问虚拟Dom节点。咱们能够在这个方法中与其余JavaScript框架进行集成、处理一些渲染后的逻辑(好比说绑定一些事件等)、发送Ajax请求或是设置定时器方法(setTimeout/setInterval)等。
componentWillReceiveProps:初始化渲染时不会被调用,只有当props放生改变时才会被调用。该方法能够做为React在prop传入以后,render()方法执行以前更新state的合适时机。旧的props能够经过this.props获取到。
componentWillUnmount:在组件从DOM中移除的时候马上被调用咱们能够在该方法中执行任何须要的清理,好比无效的定时器,或者清除在componentDidMount()中建立的DOM元素等。
另外React还提供了一个用来优化渲染的周期函数shouldComponentUpdate,它能够用来判断一次状态改变是否须要从新渲染,更多生命周期函数介绍参见这里
React有内建的跨浏览器的事件系统,你能够在组件里以添加属性的方式绑定事件和相应的处理函数,如上面例子中ParentComponent组件里经过设置onClick属性绑定事件的处理函数handleClick。这种事件绑定方法极大的方便了事件操做,不用再像之前先定位到Dom节点,再经过addEventListener绑定事件,还要用removeEventListener解绑。当组件注销时,react会自动帮咱们解绑事件。更多React支持的事件,请参见这里。
若是你是刚刚接触React,那么当你阅读官方的tutorial文档时,会以为这玩意原来这么简单,无非是将页面功能组件化,调用为数很少的几个api,按照教程一步一步来很快就编写出一个评论应用。当你想利用脚手架快速搭建企业级的React开发环境时,你会也许会用到react-starter-kit,可是他却有点“名不符实”,由于匮乏的文档说明,让其对新手并不友好。相比之下react-redux-universal-hot-example则更加易于理解和学习。值得注意的是学习React,仅仅是学习框架自己是不够,由于当你阅读代码的过程当中,你会发现npm是基本的;webpack也是必须的;你还要知道ES6相关语法,相应的你要懂得使用Babel来转换ES5;更进阶你要开始学习全新的程序设计模式Flux和Redux来管理应用的状态等等。学习这些知识不可能一蹴而就,当你遇到某个解不开的点时,不妨先跳过,随着学习的深刻,当你回头来看时就会有种恍然大悟的感受。
The Only React.js Tutorials and Resources You’ll Need,介绍了不少React学校相关的资源,上面的每篇文章都值得一读。
React的一些概念对React的一些概念进行了阐述。
React.js Tutorial Pt 1: A Comprehensive Guide to Building Apps with React.js 很是不错的tutorial,做者思路很清晰,一步步讲解而且附有实例,系列文章还没更新完
React 入门实例教程,阮一峰写的实例教程,里面包含了各个关键知识点的实例代码。
es5-es6语法对比 ,比较详细的react es5-es6语法对照表,看完它对理解一些项目代码比较有用
react style guide,react 代码书写风格的一篇文章,遵照你们都在用的一些规则,对阅读源码颇有帮助。
浅谈 React、Flux 与 Redux,对React、Flux、Redux之间的关系进行了很好的阐述。
Full-Stack Redux Tutorial,这篇文章介绍了如何使用Redux构建同构应用,经过一个投票应用,全面介绍了整个开发流程,很是值得阅读。