背景
在使用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