前陣子嘗試用React開發了一個項目的前端,寫起來還算是流暢。將頁面中各模塊進行分割並形成組件之後,管理起來更加的方便,代碼的可讀性也相對於傳統的麪條式編程有很大的提高。React相對於Angular來說,我個人認爲是更加輕量化的,它更注重於MVC中的V。
舉個例子,開發中常常會用到button這個元素,我們會給button加上樣式、行爲等等。一個項目中button可能是被經常重複使用的,他的樣式也可能幾乎是一摸一樣的,無非是color和size的區別而已。按照傳統的寫法,可能代碼是下面這個樣子的:
<button onClick='function(){alert('clicked!')}' class='btn btn-green btn-large'>點我</button>
如果click事件是有默認事件的,class默認也是綠色,那麼每次都寫這一堆是有點煩了,如果我們將這個button視爲一個組件,那麼我們可以給它設置默認的樣式和行爲,並通過傳不同的值給組件改變它的狀態。我們來個React版本的。
var Button = React.createClass({
propTypes:{
children: React.PropTypes.any,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
onClick: React.PropTypes.func,
style: React.PropTypes.object,
type: React.PropTypes.oneOf(['submit', 'button'])
},
getInitialState:function(){
return {
disabled:this.props.disabled,
className:'btn-green',
type: this.props.type ? this.props.type : 'button',
text: null
}
},
componentWillReceiveProps:function(newProps){
if (newProps.disabled !== this.props.disabled) {
this.setState({ disabled: newProps.disabled })
}
},
text:function(text){
this.setState({
text:text
});
},
handleClick:function() {
if (this.props.onClick) {
this.props.onClick()
}
},
render:function(){
return (
<button className={this.state.className}
disabled={this.state.disabled}
type={this.state.type}
style={this.props.style}
onClick={this.handleClick.bind(this)}>
{this.state.text || this.props.children}
</button>
);
}
});
這裏Button就視爲一個模塊或者組件,它接收父組件的值來改變它的默認狀態,當沒有值傳入時,使用默認的內部值。
爲了達到最開始那個button的效果,我們可以這麼使用它:
React.render(
<div>
<Button size='large' onClick='function(){alert('click')}'>
</div>
, document.getElementById('container'));
雖然這樣看上去好像並沒有和傳統方式有太大的區別,而且還多了一堆代碼去定義這個button組件,得不償失,但是這僅僅只是組件化的開始,面對更復雜的組件時,它的好處就體現出來了。看看下面的例子:
需求是我們需要一個搜索框,在用戶輸入的同時通過異步請求進行搜索,同時爲了防止用戶輸入速度快導致請求過於頻繁,在用戶輸入每個字後延遲300ms進行搜索,如果在這段時間內用戶任然有輸入,那麼就再延遲300ms,也就是高頻防抖。
以傳統的方式來,我們得先寫個input,然後把這個input包裝成search input的樣子,然後註冊事件,並在事件中設置延遲函數,然後才真正執行搜索動作。。。等另一個頁面又有搜索時,重複剛纔的步驟。如果把SearchInput設想成一個組件,那麼它會是下面這個樣子的。
var SearchInput = React.createClass({
inputTimeout:null,
propTypes:{
size: React.PropTypes.string,
onInput: React.PropTypes.func,
delay: React.PropTypes.number,
disabled: React.PropTypes.bool
},
getInitialState:function(){
return {
size: this.props.size ? this.props.size : '',
delay: this.props.delay ? this.props.delay : 300
}
},
handleInput: function(event){
var value = event.target.value;
if(this.inputTimeout){
window.clearTimeout(this.inputTimeout);
}
var that = this;
this.inputTimeout = setTimeout(function(){
that.props.onInput(value);
},this.state.delay);
},
render: function(){
var sizeClasss = this.state.size ? "topcoat-search-input--"+this.state.size :
"topcoat-search-input";
return (
<input type="search"
placeholder='search'
onInput={this.handleInput.bind(this)}
className={sizeClasss}
disabled={this.props.disabled}
/>
);
}
});
我們將延遲的時間和是否禁用等信息當做屬性傳給SearchInput組件,並將延遲操作的邏輯等封裝在組件內部,以後我們就不用關心這些了,直接使用即可。
React.render(
<div>
<SearchInput delay=500 onClick='function(value){alert(value)}'></SearchInput>
</div>
, document.getElementById('container'));
我們傳入delay與搜索邏輯函數即可,input的value也會傳入搜索邏輯函數。
當然,還有更復雜的情況,我們可以將邏輯封裝在組件中,使用的人只需要通過屬性改變組件的狀態,而不需要關心組件狀態改變的邏輯。
最近嘗試封裝一些通用的React UI組件,挑選了Topcoat樣式去封裝,感興趣的朋友可以點擊下面這個鏈接
https://github.com/ForeverPx/react-topcoat
文章作者:forevercjl
原文鏈接:www.foreverpx.cn
轉載請註明出處。