//ReactDOM.render(reactWhat,domWhere)在瀏覽器中渲染應用的一種途徑
//React.DOM表示預約義好的HTML元素集合
//React.DOM.h1(attributes,children)表示一個預約義的React 組件
//h1()第一個參數接收一個對象,用於指定該組件的任何屬性(好比id屬性,三個特殊屬性class:className,for:htmlFor,style:對象形式賦值)。
//h1()第二個參數定義了該組件的子元素(Hello world!)
//document.getElementById("app") 方法訪問DOM 節點,告訴React 須要把應用渲染在頁面的哪一個部分
ReactDOM.render(React.DOM.h1({
id: 'my-heading'
}, 'Hello world!'), document.getElementById('app'));
// JSX版本
ReactDOM.render(
<h1 id="my-heading" > <span><em>Hell < /em>o</span > world! < /h1>, document.getElementById('app') ); 複製代碼
//自定義新組件
var Component = React.createClass({
//該對象須要包含一個名爲render() 的方法來顯示組件
render: function () {
//該方法必須返回一個React 組件,不能只返回文本內容。
return React.DOM.span(null, 'I\'m so custom');
}
});
//使用自定義組件
ReactDOM.render(
//React.createElement() 是建立組件「實例」的方法之一
React.createElement(Component),
//若是你想建立多個實例,還有另外一種途徑,就是使用工廠方法:React.createFactory(Component);
document.getElementById('app')
);
複製代碼
//自定義的組件能夠接收屬性,全部屬性均可以經過this.props對象獲取
var Component = React.createClass({
//propTypes是可選的,聲明組件須要接收的屬性列表及其對應類型
propTypes: {
//清晰地指明瞭name 屬性是一個必須提供的字符串值
name: React.PropTypes.string.isRequired,
middleName: React.PropTypes.string,
},
//getDefaultProps() 方法返回一個對象,併爲每一個可選屬性(不帶.isRequired的屬性)提供了默認值。
getDefaultProps: function () {
return {
middleName: 'chris'
};
},
render: function () {
//請把this.props 視做只讀屬性。從父組件傳遞配置到子組件時,屬性很是重要
return React.DOM.span(null, 'My name is ' + this.props.name);
}
});
ReactDOM.render(
React.createElement(Component, {
name: 'Bob'
}),
document.getElementById('app')
);
複製代碼
var TextAreaCounter = React.createClass({
propTypes: {
text: React.PropTypes.string,
},
getDefaultProps: function () {
return {
text: '',
};
},
// 無狀態版本
render: function () {
return React.DOM.div(null,
//文本框使用了defaultValue 屬性,而不是你在常規HTML 中習慣使用的文本子元素
React.DOM.textarea({
defaultValue: this.props.text,
}),
React.DOM.h3(null, this.props.text.length)
);
},
// 有狀態版本(狀態state負責組件內部數據的維護)
_textChange: function (ev) {//數據發生改變時(即用戶在文本框中輸入內容時),組件能夠經過一個事件監聽器更新state
this.setState({//改變state 必須使用this.setState() 方法。該方法接收一個對象參數,並把對象與this.state 中已存在的數據進行合併
text: ev.target.value,
});
},
getInitialState: function () {//在初始化時,定義state中須要包含的屬性,以保證能夠經過this.state.text訪問屬性
return {
text: this.props.text,
};
},
render: function () {
return React.DOM.div(null,
//文本框使用了defaultValue 屬性,而不是你在常規HTML 中習慣使用的文本子元素
React.DOM.textarea({
value: this.state.text,
//React 使用了合成事件來消除瀏覽器之間的不一致狀況,React 在事件處理中使用駝峯法命名。
//當用戶輸入時觸發。而不是像原生DOM 事件那樣,在用戶結束輸入並把焦點從輸入框移走時才觸發。
onChange: this._textChange,
}),
React.DOM.h3(null, this.state.text.length)
);
}
});
// 使用自定義組件
ReactDOM.render(
React.createElement(TextAreaCounter, {
text: "Bob",
}),
document.getElementById("app")
);
複製代碼
var myTextAreaCounter = ReactDOM.render(
React.createElement(TextAreaCounter, {
defaultValue: "Bob",
}),
document.getElementById("app")
);
//設置了新的state 值
myTextAreaCounter.setState({ text: "Hello outside world!" });
//獲取了React 建立的父元素DOM 節點的引用
var reactAppNode = ReactDOM.findDOMNode(myTextAreaCounter);
//獲取DOM 結構中首個<div id="app"> 節點。這也是你讓React 進行渲染的位置:
reactAppNode.parentNode === document.getElementById('app'); // true
//訪問組件的屬性和狀態
myTextAreaCounter.props; // Object { defaultValue: "Bob"}
myTextAreaCounter.state; // Object { text: "Hello outside world!"}
複製代碼
//這個方法會接收新屬性對象,讓你能夠根據新屬性設置state
componentWillReceiveProps: function(newProps) {
this.setState({
text: newProps.defaultValue,
});
};
複製代碼
設置默認的props
,也能夠用dufaultProps
設置組件的默認屬性. 對於組件類來講只調用一次,該組件類的全部後續應用,getDefaultPops
將不會再被調用html
在使用es6
的class語法時是沒有這個鉤子函數的,能夠直接在constructor
中定義this.state
。react
對於組件的每一個實例來講,這個方法的調用有且只有一次,用來初始化每一個實例的 state
,在這個方法裏,能夠訪問組件的 this.props
。es6
getInitialState
和 getDefaultPops
的調用是有區別的,getDefaultPops
是對於組件類來講只調用一次,後續該類的應用都不會被調用, 而 getInitialState
是對於每一個組件實例來說都會調用,而且只調一次。算法
組件初始化以後,首次渲染以前調用,之後組件更新不調用,整個生命週期只調用一次,是在render
方法調用以前修改 state
的最後一次機會。canvas
react
最重要的步驟,建立虛擬dom
,進行diff
算法,更新dom
樹都在此進行。此時就不能更改state
了。 該方法會建立一個虛擬DOM
,用來表示組件的輸出。對於一個組件來說,render
方法是惟一一個必需的方法。瀏覽器
render
方法須要知足下面幾點:性能優化
(1)只能經過 this.props
和 this.state
訪問數據(不能修改)數據結構
(2)能夠返回 null
,false
或者任何React
組件app
(3)只能出現一個頂級組件,不能返回一組元素dom
(4)不能改變組件的狀態
(5)不能修改DOM
的輸出
render
方法返回的結果並非真正的DOM
元素,而是一個虛擬的表現,相似於一個DOM tree
的結構的對象。react
之因此效率高,就是這個緣由。
組件渲染以後調用,只調用一次。 該方法被調用時,已經渲染出真實的 DOM
,能夠再該方法中經過 this.getDOMNode()
訪問到真實的 DOM
(推薦使用 ReactDOM.findDOMNode()
)。
因爲組件並非真實的 DOM
節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)
。只有當它插入文檔之後,纔會變成真實的 DOM
。有時須要從組件獲取真實 DOM
的節點,這時就要用到 ref
屬性:
var Area = React.createClass({
render: function () {
this.getDOMNode(); //render調用時,組件未掛載,這裏將報錯
return <canvas ref='mainCanvas' > }, componentDidMount: function () { var canvas = this.refs.mainCanvas.getDOMNode(); //這是有效的,能夠訪問到 Canvas 節點 } }); 複製代碼
須要注意的是,因爲 this.refs.[refName]
屬性獲取的是真實 DOM
,因此必須等到虛擬 DOM
插入文檔之後,才能使用這個屬性,不然會報錯。
此時組件已經渲染好而且用戶能夠與它進行交互,好比鼠標點擊,手指點按,或者其它的一些事件,致使應用狀態的改變,你將會看到下面的方法依次被調用
組件的 props
屬性能夠經過父組件來更改,這時,componentWillReceiveProps
未來被調用。能夠在這個方法裏更新 state
,以觸發 render
方法從新渲染組件。
componentWillReceiveProps: function(nextProps) {
if (nextProps.checked !== undefined) {
this.setState({
checked: nextProps.checked
})
}
}
複製代碼
react
性能優化很是重要的一環。 組件接受新的state
或者props
時調用,咱們能夠在此對比先後兩個props
和state
是否相同。 若是相同,則返回false
阻止更新,由於相同的屬性狀態必定會生成相同的dom
樹,這樣就不須要創造新的dom
樹和舊的dom
樹進行diff
算法對比,節省大量性能
若是你肯定組件的 props
或者state
的改變不須要從新渲染,能夠經過在這個方法裏經過返回 false
來阻止組件的從新渲染,返回 false
則不會執行 render
以及後面的 componentWillUpdate
,componentDidUpdate
方法。
該方法是非必須的,而且大多數狀況下不會使用。
這個方法和 componentWillMount
相似,在組件接收到了新的 props
或者 state
即將進行從新渲染前,componentWillUpdate(object nextProps, object nextState)
會被調用。 注意此時能夠修改state
,但最好不要在此方面裏再去更新 props
或者 state
。
組件渲染
這個方法和 componentDidMount
相似,在組件從新被渲染以後,componentDidUpdate(object prevProps, object prevState)
會被調用。能夠在這裏訪問並修改 DOM
。
組件將要卸載時調用,一些事件監聽和定時器須要在此時清除。
// 組件卸載
React.unmountComponentAtNode(this.props.containerNode[0]);
複製代碼