幫助你們進一步瞭解React,幫助你們寫出高效的可讀性好的代碼。html
/** * @fileoverview react組件內方法編寫順序 */ define(function(require, exports, module) { var ReactComponent = React.createClass({ propTypes: {}, contextTypes: {}, childContextTypes: {}, getDefaultProps: function() {}, getInitialState: function() {}, getChildContext: function() {}, // 組件生命週期方法 componentWillMount: function() {}, componentDidMount: function() {}, componentWillReceiveProps: function() {}, shouldComponentUpdate: function() {}, componentWillUpdate: function() {}, componentDidUpdate: function() {}, componentWillUnmount: function() {}, // 業務邏輯相關的處理方法 loadData: function() {}, parseData: function() {}, handleClick: function() {}, // 自動渲染虛擬DOM方法 render: function() {} }); module.exports = ReactComponent; });
render
,放在底部容易尋找。【正確】:react
return ( <div> <h2>title</h2> <div>content</div> </div> );
【錯誤】:git
return ( <h2>title</h2> <div>content</div> );
沒有子節點的React組件,自閉合方式。github
【推薦】ajax
return <ComponentView/>;
【不推薦】數組
return <ComponentView></ComponentView>;
含有子節點的React組件promise
【推薦】異步
return ( <ComponentView> <ComponentChild/> </ComponentView> );
組件含有屬性。ui
【推薦】this
// 屬性少,一行能放下放在一行 return <ComponentView className="list-wrap" rel="list"/>; // 屬性多,>3個。多行顯示。 return ( <ComponentView className="list-wrap" rel="list" onClick={this.handleClick} ... /> ); // 若是屬性不少的話,推薦使用以下方式。把全部屬性放在一個對象裏面。 var props = { className: 'list-wrap', rel: 'list', onSuccess: this.onSuccess onError: this.onSuccess }; return <ComponentView {...props}/>;
【不推薦】
return <ComponentView className="list-wrap" rel="list"/>;
子組件的渲染條件根據props\state的數據
【推薦】:先聲明-》根據條件處理子組件-》{ReactElement}
module.exports = React.createClass({ getInitialState: function() { return { dataLoading: true }; }, render: function() { // 聲明一個變量。 var loading; if (this.state.dataLoading) { loading = <Loading/>; } // 在JSX模板中,使用大括號{},引入子組件。 return ( <div> {loading} </div> ); } });
遍歷數組經常使用方式。2種方式:map方法和forEach方法。
【Array.map方法】
var List = React.createClass({ getDefaultProps: function() { return { data: [{ name: 'test1' },{ name: 'test2' }] }; }, getInitialState: function() { return { data : this.props.data }; }, render: function(){ return ( <ul> { this.state.data.map(function(item, index){ return <li>{item.name}</li> }) } </ul> ); } });
【Array.forEach方法】
var List = React.createClass({ getDefaultProps: function() { return { data: [{ name: 'test1' },{ name: 'test2' }] }; }, getInitialState: function() { return { data : this.props.data }; }, render: function(){ var items; this.state.data.forEach(function(item, index){ items.push(<li>{item.name}</li>); }) return ( <ul> {items} </ul> ); } });
若是想在this.setState以後立馬獲取新的state的值或者進行一些操做,能夠在回調中執行
this.setState({ coin: 111 }, funtion(){ console.log(this.state); // 新的state對象 // 其餘指定操做 }) console.log(this.state); // 舊的state對象
refs getDOMNode()
使用步驟:
ref="name"
屬性對一個 DOM節點進行標記this.refs.name.getDOMNode()
獲取到這個節點的原生 DOM。一、示例(原生組件-》HTML標籤):
獲取原生DOM節點以後,就能夠使用它擁有的屬性以及方法。
<input ref="myInfo" data-id="xxx"/> var input = this.refs.myInfo.getDOMNode(); // 獲取value var inputValue = input.value; // 自定義屬性 var inputAttr = input.getAttributes('data-id'); // 失去焦點 input.blur(); // 得到焦點 input.focus();
二、示例(自定義組件-》React組件):
<List ref="list" data={data} /> var list = this.refs.list.getDOMNode(); // 修改子組件實例的狀態,觸發render list.setState({ data: newData }); // 能夠使用子組件實例中的方法 ...
【注意】:
因爲 this.refs.name.getDOMNode()
獲取到是真實的DOM,必須等虛擬DOM節點插入文檔中後,才能用到這個屬性,不然就會報錯。
【推薦】:能夠在 componentDidMount
方法中調用、存儲DOM節點。
【錯誤使用】:在render
方法中訪問refs
屬性。報錯!!
使用場景:移除組件前,這裏能夠作一些清除工做,例如清除內存,解除事件的監聽等等。
被觸發的條件:
componentWillUnmount
會被觸發。ReactDOM.unmountComponentAtNode(container)
。container中的全部組件都會被卸載,全部子組件的componentWillUnmount
方法都會觸發。componentWillUnmount
方法不會觸發的例如:
var Loading = React.createClass({ getDefaultProps: function(){ return { text: '加載中' }; }, componentWillUnmount: function(){ console.log('componentWillUnmount'); }, render: function(){ return ( <div className="loading">{this.props.text}</div> ); } }); module.exports = React.createClass({ getInitialState: function() { return { dataLoading: true }; }, render: function() { var loading = null; if (this.state.dataLoading) { loading = <Loading/> } return ( <div> {loading} </div> ); } }); // 當this.state.dataLoading = false時候,<Loading/>被卸載。<Loading/>組件中的componentWillUnmount在組件卸載前會被觸發。
【推薦】在componentDidMount
方法中異步加載初始數據。
var AjaxC = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 請求成功,更新state,觸發render方法更新視圖UI self.setState({ data: res.data }) } }); }, render: function(){ //.... } });
子組件的數據由父組件提供,父組件經過props將數據傳給子組件。
組件嵌套結構 - ParentComponent - ChildComponent
實現方式:componentWillReceiveProps
var ParentComponent = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 請求成功,更新state,觸發render方法更新視圖UI self.setState({ avatar: res.data }) } }); }, render: function(){ return ( <div> <div> 圖片地址: {this.state.avatar} </div> <ChildComponent avatar={this.state.avatar} ref="child"/> </div> ); } }); var ChildComponent = React.createClass({ getInitialState: function() { return this.copyPropsToState(this.props); }, /** * 單獨一個方法。組件狀態處理,依賴props */ copyPropsToState: function(props) { return { avatar: props.avatar } }, componentWillReceiveProps: function(nextProps) { this.setState(this.copyPropsToState(nextProps)); }, render: function(){ return ( <img ref="avatar" src={this.state.avatar}/> ); } });
實現方式2, 在父組件中調用this.refs.xxx.setState();
var ParentComponent = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 請求成功,更新state,觸發render方法更新視圖UI self.setState({ avatar: res.data }) self.refs.child.setState({ avatar: res.data }) } }); }, render: function(){ return ( <div> <div> 圖片地址: {this.state.avatar} </div> <ChildComponent avatar={this.state.avatar} ref="child"/> </div> ); } }); var ChildComponent = React.createClass({ getInitialState: function() { return { avatar: this.props.avatar || "" } }, render: function(){ return ( <img ref="avatar" src={this.state.avatar}/> ); } });
【總結】:
使用React.createClass() 建立React組件:
JSX中的事件自動綁定、而且在組件卸載的時候,自動解除綁定。
React.createClass({ render: function(){ return ( <input type="text" onClick={this.handleClick}/> ); }, handleClick: function(e){ // this爲當前組件實例對象。 this.setStata({ data: '11' }) } }); // 若事件須要傳參數 React.createClass({ render: function(){ return ( <input type="text" onClick={this.handleClick.bind(this, '傳的參數')}> ); }, /** * @param data 傳的參數 * @param e event對象 */ handleClick: function(data, e){ console.log(data) // => "傳的參數" // 獲取發生點擊事件的DOM節點,使用方式同之前。 var target = e.currentTarget; // this爲當前組件實例對象。 this.setStata({ data: '11' }) } });
擴展,暫時不須要掌握【ES6語法建立React組件】
JSX中的事件,須要手動綁定到當前組件的實例對象上,使得事件方法中的this指向的是該組件實例對象.
<input type="text" onClick={this.handleClick.bind(this)}/>
【推薦】:在 componentDidMount
方法中綁定普通的DOM事件,而且在componentWillUnmount
中移除這些事件
var Scroll = React.createClass({ componentDidMount: function(){ // 請求數據 this.loadData(); // 綁定事件 this.bindEvent(); }, componentWillUnmount: function(){ console.log('off scroll event'); $(window).off('scroll'); }, loadData: function(){ //... }, bindEvent: function(){ console.log('bind scroll event'); $(window).on('scroll', function() { // 事件滾動操做 }); }, render: function(){ } });
https://facebook.github.io/react/docs/context-zh-CN.html
實踐場景:
App中全局信息,組件嵌套層級很深,處於深處的子組件須要用到頂級的數據。若數據經過props方式一級一級往下傳,很麻煩。能夠經過此方式,讓子組件訪問到該數據
// 1. 在上級組件中,經過childContextTypes屬性和getChildContext方法,定義組件可訪問的數據(還能夠是方法)。
var Parent = React.createClass({
childContextTypes: {
goldCoin: React.PropTypes.any,
getColdCoin: React.PropTypes.any,
updateGoldCoin:React.PropTypes.any,
},
getChildContext: function(){
return {
goldCoin: this.state.goldCoin, // 第一次渲染組件時,就固定了子組件獲取的值。
getGoldCoin: this.getGoldCoin, // 若是n數據是變動的,推薦使用方法去獲取
updateGoldCoin: this.updateGoldCoin
}
},
updateGoldCoin: function(goldCoin){
this.setState({
goldCoin: goldCoin
});
},
getGoldCoin: function(){
return Number(this.state.goldCoin);
}
})
// 2. 子組件中,能夠經過this.context.xxx訪問上級頂級的數據或者方法
var Child = React.createClass({
contextTypes: {
goldCoin: React.PropTypes.any,
getColdCoin: React.PropTypes.any,
updateGoldCoin: React.PropTypes.any
},
...
render: function(){
...
},
...
updateGoldCoin: function(){
var goldCoin = this.context.getGoldCoin();
var newGoldCoin = '333333';
this.context.updateGoldCoin(newGoldCoin);
}
});