React提供了和以往不同的方式来看待视图,它以组件开发为基础。组件是React的核心概念,React 容许将代码封装成组件(component),而后像插入普通 HTML 标签同样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。对React应用而言,你须要分割你的页面,使其成为一个个的组件。也就是说,你的应用是由这些组件组合而成的。你能够经过分割组件的方式去开发复杂的页面或某个功能区块,而且组件是能够被复用的。这个过程大概相似于用乐高积木去瓶装不一样的物体。咱们称这种编程方式称为组件驱动开发。javascript
React是能够同时渲染HTML标签与组件的,可是要注意的是,通常Tags元素都是小写开头,而Component都是以大写字母开头,如下面为例:html
var myDivElement = <div className="foo" />; React.render(myDivElement, document.getElementById('example'));
而若是须要渲染一个Component:java
var MyComponent = React.createClass({/*...*/}); var myElement = <MyComponent someProperty={true} />; React.render(myElement, document.getElementById('example'));
组件的生命周期分红三个状态:node
Mounting:已插入真实 DOM,即Initial Renderreact
Updating:正在被从新渲染,即Props与State改变git
Unmounting:已移出真实 DOM,即Component Unmountgithub
React 为每一个状态都提供了两种处理函数,will 函数在进入状态以前调用,did 函数在进入状态以后调用,三种状态共计五种处理函数。编程
componentWillMount()canvas
componentDidMount()数组
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否从新渲染时调用
这里能够看出,Props比State的改变会有多出一个shouldComponentUpdate的回调方法。
若是须要判断某个组件是否挂载,能够isMounted()方法进行判断,能够用该方法来确保异步调用中的setState与forceUpdate方法不会被误用。不过该方法在ES6的类中已经被移除了,在将来的版本中也会被逐步移除。
总结而言,一个完整的React Component的写法应该以下:
/** * @jsx React.DOM */ var React = require('react'), MyReactComponent = React.createClass({ // The object returned by this method sets the initial value of this.state getInitialState: function(){ return {}; }, // The object returned by this method sets the initial value of this.props // If a complex object is returned, it is shared among all component instances getDefaultProps: function(){ return {}; }, // Returns the jsx markup for a component // Inspects this.state and this.props create the markup // Should never update this.state or this.props render: function(){ return (<div></div>); }, // An array of objects each of which can augment the lifecycle methods mixins: [], // Functions that can be invoked on the component without creating instances statics: { aStaticFunction: function(){} }, // -- Lifecycle Methods -- // Invoked once before first render componentWillMount: function(){ // Calling setState here does not cause a re-render }, // Invoked once after the first render componentDidMount: function(){ // You now have access to this.getDOMNode() }, // Invoked whenever there is a prop change // Called BEFORE render componentWillReceiveProps: function(nextProps){ // Not called for the initial render // Previous props can be accessed by this.props // Calling setState here does not trigger an an additional re-render }, // Determines if the render method should run in the subsequent step // Called BEFORE a render // Not called for the initial render shouldComponentUpdate: function(nextProps, nextState){ // If you want the render method to execute in the next step // return true, else return false return true; }, // Called IMMEDIATELY BEFORE a render componentWillUpdate: function(nextProps, nextState){ // You cannot use this.setState() in this method }, // Called IMMEDIATELY AFTER a render componentDidUpdate: function(prevProps, prevState){ }, // Called IMMEDIATELY before a component is unmounted componentWillUnmount: function(){ } }); module.exports = MyReactComponent;
设置默认的Props.
this.props 对象的属性与组件的属性一一对应,可是有一个例外,就是 this.props.children 属性。它表示组件的全部子节点。
var NotesList = React.createClass({ render: function() { return ( <ol> { this.props.children.map(function (child) { return <li>{child}</li> }) } </ol> ); } }); React.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body );
其效果图以下所示:
enter description here
React.createClass({ propTypes: { // You can declare that a prop is a specific JS primitive. By default, these // are all optional. optionalArray: React.PropTypes.array, optionalBool: React.PropTypes.bool, optionalFunc: React.PropTypes.func, optionalNumber: React.PropTypes.number, optionalObject: React.PropTypes.object, optionalString: React.PropTypes.string, // Anything that can be rendered: numbers, strings, elements or an array // containing these types. optionalNode: React.PropTypes.node, // A React element. optionalElement: React.PropTypes.element, // You can also declare that a prop is an instance of a class. This uses // JS's instanceof operator. optionalMessage: React.PropTypes.instanceOf(Message), // You can ensure that your prop is limited to specific values by treating // it as an enum. optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), // An object that could be one of many types optionalUnion: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, React.PropTypes.instanceOf(Message) ]), // An array of a certain type optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), // An object with property values of a certain type optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), // An object taking on a particular shape optionalObjectWithShape: React.PropTypes.shape({ color: React.PropTypes.string, fontSize: React.PropTypes.number }), // You can chain any of the above with `isRequired` to make sure a warning // is shown if the prop isn't provided. requiredFunc: React.PropTypes.func.isRequired, // A value of any data type requiredAny: React.PropTypes.any.isRequired, // You can also specify a custom validator. It should return an Error // object if the validation fails. Don't `console.warn` or throw, as this // won't work inside `oneOfType`. customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error('Validation failed!'); } } }, /* ... */ });
React不提倡数据的双向绑定,而在用户行为下面产生的数据更新,React建议仍是经过事件机制来处理。譬以下述例子中,输入框文本内容的改变,仍是经过onChange事件,而后出发状态机的变化。
var LikeButton = React.createClass({ getInitialState: function() { return {liked: false}; }, handleClick: function(event) { this.setState({liked: !this.state.liked}); }, render: function() { var text = this.state.liked ? 'like' : 'haven\'t liked'; return ( <p onClick={this.handleClick}> You {text} this. Click to toggle. </p> ); } }); React.render( <LikeButton />, document.getElementById('example') );
参考资料
Props VS State
组件的主要职责是将原始数据转化为HTML中的富文本格式,而Props与State协做完成这件事,换言之,Props与State的并集便是所有的原始数据。Props与State之间也是有不少交集的,譬如:
Props与State都是JS对象。
Props与State的值的改变都会触发界面的从新渲染。
Props与State都是肯定性的,即在肯定的Props或者State的值的状况下都会得出相同的界面。
不过Props顾名思义,更多的是做为Component的配置项存在。Props每每是由父元素指定而且传递给本身的子元素,不过自身每每不会去改变Props的值。另外一方面,State在组件被挂载时才会被赋予一个默认值,而经常在与用户的交互中发生更改。每每一个组件独立地维护它的整个状态机,能够认为State是一个私有属性。他们的对好比下:
描述 | Props | State |
---|---|---|
是否能够从父元素获取初始值 | Yes | Yes |
是否能够被父元素改变 | Yes | No |
是否能够设置默认值 | Yes | Yes |
是否能够在组件内改变 | No | Yes |
是否能够设置为子元素的初始值 | Yes | Yes |
是否能够在子元素中改变 | Yes | No |
上文中说起过,一种利用组件内包裹的方式动态定义组件的方式,能够利用Props的children属性来获取全部包裹住的Dom对象。
React主打的是组件驱动型编程,每每能够将一个大的组件拆分为几个小的组件,这里以头像控件为例:
var Avatar = React.createClass({ render: function() { return ( <div> <ProfilePic username={this.props.username} /> <ProfileLink username={this.props.username} /> </div> ); } }); var ProfilePic = React.createClass({ render: function() { return ( <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} /> ); } }); var ProfileLink = React.createClass({ render: function() { return ( <a href={'https://www.facebook.com/' + this.props.username}> {this.props.username} </a> ); } }); React.render( <Avatar username="pwh" />, document.getElementById('example') );
有时候在某个组件内调用另外一个组件,并不会进行渲染,譬如:
class Home extends React.Component { render() { return ( <div> <map/> </div> ); } } var map = React.createClass({ render: function() { return ( <div id="map-canvas"> <span>hello</span> </div> ); } });
这里的map并不会被识别,应该把map变为Map,能够参考这里。
虽然组件的原则就是模块化,彼此之间相互独立,可是有时候不一样的组件之间可能会共用一些功能,共享一部分代码。因此 React 提供了 mixins
这种方式来处理这种问题。Mixin 就是用来定义一些方法,使用这个 mixin 的组件可以自由的使用这些方法(就像在组件中定义的同样),因此 mixin 至关于组件的一个扩展,在 mixin 中也能定义“生命周期”方法。
好比一个定时器的 mixin:
var SetIntervalMixin = { componentWillMount: function() { this.intervals = []; }, setInterval: function() { this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { this.intervals.map(clearInterval); } }; var TickTock = React.createClass({ mixins: [SetIntervalMixin], // Use the mixin getInitialState: function() { return {seconds: 0}; }, componentDidMount: function() { this.setInterval(this.tick, 1000); // Call a method on the mixin }, tick: function() { this.setState({seconds: this.state.seconds + 1}); }, render: function() { return ( <p> React has been running for {this.state.seconds} seconds. </p> ); } }); React.render( <TickTock />, document.getElementById('example') );
React 的 mixins
的强大之处在于,若是一个组件使用了多个 mixins,其中几个 mixins
定义了相同的“生命周期方法”,这些方法会在组件相应的方法执行完以后按 mixins 指定的数组顺序执行。