關於RN listview item ref

背景

在使用React Native的過程中,使用ListView渲染一個列表時,有時候需要操作item中某個控件,比如調用該控件的某個方法,我們知道要調用方法之前需要獲取到該控件的對象引用,那麼我們就開始嘗試獲取控件的引用對象。

項目中的實際場景是:有一個電影觀看歷史列表,列表的每一行有個複選框CheckBox,勾選這一行的複選框後支持刪除操作,雖然每一行的單獨操作可以實現勾選/取消功能,但是同時又要實現全選/反選操作,這時候當點擊全選按鈕後,需要遍歷每一個item中的CheckBox進行勾選操作來實現全選功能。

遇到的問題

獲取控件的引用對象,在RN是使用ref來獲取的,ListView->renderRow,這是渲染每一行的代碼

renderRow={this._renderMovieView.bind(this)}

_renderMovieView方法

_renderMovieView(movie){
    return(
    <CheckBox
        ref="myCheckBox"
        >
    </CheckBox>)
}

movie是每一行的電影數據結構對象,CheckBox組件有一個check(isChecked)方法

如果我們像上面那樣來定義ref,這時候,通過下面的方式來獲取CheckBox對象引用

this.refs.myCheckBox.check(true)

這樣你會發現,永遠只有最後一個有響應,這是因爲每一行item的CheckBox的ref名稱是相同的,導致只有最後渲染的那一行的CheckBox的ref是有效的。那麼,我們就想爲每一行CheckBox定義唯一的ref

_renderMovieView(movie){
    return(
    <CheckBox
        ref={`myCheckBox${movie.id}`}
        >
    </CheckBox>)
}

需要注意的是這裏的引號是反引號(鍵盤左上角1鍵左邊的那個鍵),不是單引號也不是雙引號

這裏movie有個id屬性,通過movie的id唯一性來定義CheckBox ref的唯一性,這樣我們理所當然的可以像上面的方法來獲取引用對象

假設有個movie.id=1

this.refs.myCheckBox1.check(true)

這時候問題就來了,會報undefined錯誤!我的第一直覺告訴我怎麼可能會這樣!(到現在我也不知道爲什麼會這樣,有知道的可以告訴我下,畢竟我也是剛開始學習的,不懂的很多)。然後,我試着打印出this.refs,裏面確實是空,什麼也沒有,自然就undefined了,無解。。。換個方法。。。

解決方案

上面提出問題的那個方法,是RN定義ref 的其中一種方式,另一種方式還可以這樣

<CheckBox
    ref={(box)=>{
        this.myCheckBox=box;
    }}
    >
</CheckBox>

那麼就可以使用myCheckBox對象了

this.myCheckBox.check(true);

接下來我們的解決方案就是使用這種方式

var CheckBoxRefs = {};

_renderMovieView(movie){
    return(
    <CheckBox
        ref={(box)=>{
          CheckBoxRefs[`myCheckBox${movie.id}`]=box;  
        }}
        >
    </CheckBox>)
}

定義了一個CheckBoxRefs map(key/value)對象,CheckBoxRefs的key是唯一名稱,value是CheckBox引用對象(實例),然後在使用的時候如下

for (var key in CheckBoxRefs){
    var item = CheckBoxRefs[key];
    if(item){
        item.check(true);
    }
}

這樣就實現了CheckBox全選的功能了。

react native 的issues上還提供了另一種解決方案,但我還沒有驗證過,有興趣的可以去看看 Get refs to ListView rows

如果想看本章內容的完整實現代碼,可以到我的github查看ViewsHistoryScene.js

發佈了106 篇原創文章 · 獲贊 382 · 訪問量 118萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章