React,用組件化思想寫前端代碼

前陣子嘗試用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
轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章