定义组件的最简单方法是编写JavaScript函数html
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
此函数是一个有效的React组件,由于它接受单个“props”(表明属性)对象参数与数据并返回一个React元素。咱们称这些组件为“函数组件”,由于它们其实是JavaScript函数。node
class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
从React的角度来看,上述两个组件是等效的。react
以上内容来自于react官方文档es6
class Welcome extends React.CreatClass { render() { return <h1>Hello, {this.props.name}</h1>; } }
无状态组件式从React 0.14 版本开始的。为了建立纯展现组件,这种组件只负责根据传入的props来展现,不涉及到要state状态的操做。编程
其官方指出:在大部分React代码中,大多数组件被写成无状态的组件,经过简单组合能够构建成其余的组件等;这种经过多个简单而后合并成一个大应用的设计模式被提倡。segmentfault
目前Reart已发展到16.9,引入了Hook,推荐使用无状态组件。设计模式
无状态函数式组件形式上表现为一个只带有一个render方法的组件类,经过函数形式或者ES6 arrow function的形式在建立,而且该组件是无state状态的。具体的建立形式以下:
第一个参数是 props
,第二个是 context
数组
function Welcome(props, context) { return <h1>Hello, {props.name}</h1>; } ReactDOM.render(<Welcome name="whongliang" />, mountNode)
无状态组件的建立形式使代码的可读性更好,而且减小了大量冗余的代码,精简至只有一个render
方法,大大的加强了编写一个组件的便利,除此以外无状态组件还有如下几个显著的特色:less
由于组件被精简成一个render
方法的函数来实现的,因为是无状态组件,因此无状态组件就不会在有组件实例化的过程,无实例化过程也就不须要分配多余的内存,从而性能获得必定的提高。dom
this
对象无状态组件因为没有实例化过程,因此没法访问组件this
中的对象,例如:this.ref
、this.state
等均不能访问。若想访问就不能使用这种形式来建立组件
由于无状态组件是不须要组件生命周期管理和状态管理,因此底层实现这种形式的组件时是不会实现组件的生命周期方法。因此无状态组件是不能参与组件的各个生命周期管理的。
props
,一样的props
会获得一样的渲染结果,不会有反作用无状态组件被鼓励在大型项目中尽量以简单的写法来分割本来庞大的组件,将来React
也会这种面向无状态组件在譬如无心义的检查和内存分配领域进行一系列优化,因此只要有可能,尽可能使用无状态组件。
无状态组件内部实际上是可使用ref功能的,虽然不能经过this.refs访问到,可是能够经过将ref内容保存到无状态组件内部的一个本地变量中获取到。
例以下面这段代码可使用ref来获取组件挂载到dom中后所指向的dom元素:
function TestComp(props){ let ref; return (<div> <div ref={(node) => ref = node}> ... </div> </div>) }
React.createClass
是React刚开始推荐的建立组件的方式,这是ES5的原生的JavaScript来实现的React组件,其形式以下:
var InputControlES5 = React.createClass({ propTypes: {//定义传入props中的属性各类类型 initialValue: React.PropTypes.string }, defaultProps: { //组件默认的props对象 initialValue: '' }, // 设置 initial state getInitialState: function() {//组件相关的状态对象 return { text: this.props.initialValue || 'placeholder' }; }, handleChange: function(event) { this.setState({ //this represents react component instance text: event.target.value }); }, render: function() { return ( <div> Type something: <input onChange={this.handleChange} value={this.state.text} /> </div> ); } }); InputControlES6.propTypes = { initialValue: React.PropTypes.string }; InputControlES6.defaultProps = { initialValue: '' };
与无状态组件相比,React.createClass
和后面要描述的React.Component
都是建立有状态的组件,这些组件是要被实例化的,而且能够访问组件的生命周期方法。可是随着React的发展,React.createClass
形式自身的问题暴露出来:与无状态组件相比,React.createClass和后面要描述的React.Component都是建立有状态的组件,这些组件是要被实例化的,而且能够访问组件的生命周期方法。可是随着React的发展,React.createClass形式自身的问题暴露出来:
React.createClass
会自绑定函数方法(不像React.Component只绑定须要关心的函数)致使没必要要的性能开销,增长代码过期的可能性。React.createClass
的mixins
不够天然、直观;React.Component
形式很是适合高阶组件(Higher Order Components--HOC),它以更直观的形式展现了比mixins更强大的功能,而且HOC是纯净的JavaScript,不用担忧他们会被废弃。HOC能够参考无状态组件(Stateless Component) 与高阶组件。React.Component是以ES6的形式来建立react的组件的,最终会取代React.createClass形式;相对于 React.createClass能够更好实现代码复用。将上面React.createClass的形式改成React.Component形式以下:
class InputControlES6 extends React.Component { constructor(props) { super(props); // 设置 initial state this.state = { text: props.initialValue || 'placeholder' }; // ES6 类中函数必须手动绑定 this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({ text: event.target.value }); } render() { return ( <div> Type something: <input onChange={this.handleChange} value={this.state.text} /> </div> ); } } InputControlES6.propTypes = { initialValue: React.PropTypes.string }; InputControlES6.defaultProps = { initialValue: '' };
根据上面展现代码中两者定义组件的语法格式不一样以外,两者还有不少重要的区别,下面就描述一下两者的主要区别。
React.createClass建立的组件,其每个成员函数的this都有React自动绑定,任什么时候候使用,直接使用this.method便可,函数中的this会被正确设置。
const Contacts = React.createClass({ handleClick() { console.log(this); // React Component instance }, render() { return ( <div onClick={this.handleClick}></div> ); } });
React.Component建立的组件,其成员函数不会自动绑定this,须要开发者手动绑定,不然this不能获取当前组件实例对象。
class Contacts extends React.Component { constructor(props) { super(props); } handleClick() { console.log(this); // null } render() { return ( <div onClick={this.handleClick}></div> ); }
固然,React.Component有三种手动绑定方法:能够在构造函数中完成绑定,也能够在调用时使用method.bind(this)来完成绑定,还可使用arrow function来绑定。拿上例的handleClick函数来讲,其绑定能够有:
//构造函数中绑定 constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } // 使用bind来绑定 <div onClick={this.handleClick.bind(this)}></div> // 使用arrow function来绑定 <div onClick={()=>this.handleClick()}></div>
eact.createClass在建立组件时,有关组件props的属性类型及组件默认的属性会做为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的
const TodoItem = React.createClass({ propTypes: { // as an object name: React.PropTypes.string }, getDefaultProps(){ // return a object return { name: '' } } render(){ return <div></div> } })
React.Component在建立组件时配置这两个对应信息时,他们是做为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。对应上面配置以下:
class TodoItem extends React.Component { static propTypes = {//类的静态属性 name: React.PropTypes.string }; static defaultProps = {//类的静态属性 name: '' }; ... }
React.createClass建立的组件,其状态state是经过getInitialState方法来配置组件相关的状态;
React.Component建立的组件,其状态state是在constructor中像初始化组件属性同样声明的。
const TodoItem = React.createClass({ // return an object getInitialState(){ return { isEditing: false } } render(){ return <div></div> } })
class TodoItem extends React.Component{ constructor(props){ super(props); this.state = { // define this.state in constructor isEditing: false } } render(){ return <div></div> } }
Mixins(混入)是面向对象编程OOP的一种实现,其做用是为了复用共有的代码,将共有的代码经过抽取为一个对象,而后经过Mixins进该对象来达到代码复用。具体能够参考React Mixin的前世此生。
React.createClass在建立组件时可使用mixins属性,以数组的形式来混合类的集合。
var SomeMixin = { doSomething() { } }; const Contacts = React.createClass({ mixins: [SomeMixin], handleClick() { this.doSomething(); // use mixin }, render() { return ( <div onClick={this.handleClick}></div> ); } });
可是遗憾的是React.Component这种形式并不支持Mixins,至今React团队尚未给出一个该形式下的官方解决方案;可是React开发者社区提供一个全新的方式来取代Mixins,那就是Higher-Order Components,具体细节能够参考这篇文章