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 指定的數組順序執行。