一個為解決React事件綁定痛點而制定的Babel插件

babel-plugin-react-scope-binding

開發一款React應用離不開大量的事件綁定,
首先一起來回顧回顧React組件事件綁定的幾種方式。

以onClick事件為例

  1. 最粗魯的方式
class MyComponent extends Component {
    handleClick(e) {
        this.setState({
            key: 'value'
        })
    }
    render() {
        return (
            <div onClick={this.handleClick.bind(this)}></div>
        )
    }
}

直接把bind函數寫到render方法里,這是許多新手易犯的錯誤,后果是導致組件狀態變更重新渲染時重復觸發bind函數的執行,嚴重影響性能,要避免這種做法。

  1. 較好的方式
class MyComponent extends Component {
    handleClick = e => {
        this.setState({
            key: 'value'
        })
    }
    render() {
        return (
            <div onClick={this.handleClick}></div>
        )
    }
}

使用ES7類屬性箭頭函數,自動綁定類作用域,需要transform-class-properties支持,缺點是該語法屬于實驗性質,并沒有正式被劃入標準,并且把類方法當作屬性來用并不推薦。

  1. 最合理的方式
class MyComponent extends Component {
    constructor() {
        super()
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick(e) {
        this.setState({
            key: 'value'
        })
    }
    render() {
        return (
            <div onClick={this.handleClick}></div>
        )
    }
}

把bind函數寫入constructor方法中,僅當組件初始化時調用,綁定自身作用域,這是最合理的做法,缺點是組件中每增加一個新的事件,就要在constructor方法中綁定一次事件,編碼起來相當麻煩。

思考

比較以上三種方式,結論是在constructor中綁定事件最為合理。
但是,痛點在哪里?
痛點是當一個app包含大量的DOM事件需要訪問this對象時,你需要逐一手動在constructor方法中去綁定事件作用域,大量冗余重復式的代碼。
那么,如何解決這個問題?
我們可以用Babel插件實現作用域綁定自動化,減少沒必要的重復勞動力,簡化工作流程,提升開發效率。
這就是我開發這款Babel插件的起因。

有了這款插件后,你無需手動顯示綁定事件的作用域,this指針永遠指向組件本身。

因此,你可以寫出類似下面的代碼

class MyComponent extends Component {
    handleClick(e) {
        this.setState({
            key: 'value'
        })
    }
    render() {
        return (
            <div onClick={this.handleClick}></div>
        )
    }
}

開啟插件高級語法特性后,甚至可以很輕易得傳遞參數

class MyComponent extends Component {
    handleClick(e, val) {
        this.setState({
            key: 'value'
        })
        console.log(val) // 'hello'
    }
    render() {
        return (
            <div onClick={this.handleClick('hello')}></div>
        )
    }
}
插件幫我們做了什么?

在組件內部查找需要綁定作用域的事件名稱,并把bind語句注入到constructor方法中。
對于傳參語法,自動轉換成箭頭函數,類似(e) => {this.handleClick(e, item)}

實現原理

眾所周知,Babel是一款JavaScript語法轉譯器,工作流程大致可理解為先通過詞法分析把字符串形式的代碼轉換為tokens流,接著進行語法解析,把tokens流轉換為一棵抽象語法樹,然后進入轉換階段,深度遍歷抽象語法樹,對節點進行增刪改,也是你的Babel插件工作的部分,最后解析轉換后的抽象語法樹,輸出生成目標字符串文本。

抽象語法樹中每一個節點可以用一個JavaScript對象來描述,包含節點類型及其它若干屬性,你的Babel插件可以更改這些屬性或者直接替換節點、刪除節點,插入新構造的節點,用插件以訪問者模式注入的思想幫我們做更多的事。

源碼地址: https://github.com/chikara-chan/babel-plugin-react-scope-binding

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內容,還有我對于 Vue 1.0 印象不深的內容。關于...
    云之外閱讀 5,074評論 0 29
  • Vue 實例 屬性和方法 每個 Vue 實例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,241評論 0 6
  • 本筆記基于React官方文檔,當前React版本號為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,786評論 14 128
  • 自己最近的項目是基于react的,于是讀了一遍react的文檔,做了一些記錄(除了REFERENCE部分還沒開始讀...
    潘逸飛閱讀 3,470評論 1 10
  • 隨著時間流逝,有時事情自會迎刃而解。 你要是想贏,就要改變心態。勝負尚未分明,想有勝算,就要有勝利者的意志。 即使...
    葉霜序閱讀 413評論 0 0