在React Native 中,改變組件的布局樣式等可以通過props或者state來實現,但由于性能瓶頸,我們不得不放棄通過觸發render的方式來改變樣式,而是通過setNativeProps來直接更改原生組件的樣式屬性來達到相同的效果。
這里的setNativeProps方法等價于直接操作DOM節點的方法。使用這種方法修改View、Text等react Native自帶的組件,并且不會觸發組件的componentWillReceiveProps
、 shouldComponentUpdate
、 componentWillUpdate
等組件生命周期中的方法。但它不應該經常被使用,一般建議在不得不頻繁刷新而又遇到了性能瓶頸時使用。建議在使用此方法之前優先考慮setState和shouldComponentUpdate方法來解決問題。
setNativeProps 與 TouchableOpacity
TouchableOpacity這個組件就在內部使用了setNativeProps
方法來更新其子組件的透明度:
setOpacityTo: function(value) {
// Redacted: animation related code
this.refs[CHILD_REF].setNativeProps({
opacity: value
});
},
由此我們可以寫出下面這樣的代碼:子組件可以響應點擊事件,更改自己的透明度。而子組件自身并不需要處理這件事情,也不需要在實現中做任何修改。
<TouchableOpacity onPress={this._handlePress}>
<View style={styles.button}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
如果不使用setNativeProps
這個方法來實現這一需求,那么一種可能的辦法是把透明值保存到state中,然后在onPress
事件觸發時更新這個值:
getInitialState() {
return { myButtonOpacity: 1, }
},
render() {
return (
<TouchableOpacity onPress={() => this.setState({myButtonOpacity: 0.5})}
onPressOut={() => this.setState({myButtonOpacity: 1})}>
<View style={[styles.button, {opacity: this.state.myButtonOpacity}]}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
)
}
比起之前的例子,這一做法會消耗大量的計算 —— 每一次透明值變更的時候React都要重新渲染組件結構,即便視圖的其他屬性和子組件并沒有變化。一般來說這一開銷也不足為慮,但當執行連續的動畫以及響應用戶手勢的時候,只有正確地優化組件才能提高動畫的流暢度。
將setNativeProps傳遞給子組件
具體要做的就是在我們的自定義組件中再封裝一個setNativeProps
方法,其內容為對合適的子組件調用真正的setNativeProps
方法,并傳遞要設置的參數。
var MyButton = React.createClass({
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps);
},
render() {
return (
<View ref={component => this._root = component} {...this.props}>
<Text>{this.props.label}</Text>
</View>
)
},
});
這里我們使用了ref回調語法,我們向下傳遞props時使用了{...this.props}語法,(這一用法的說明請參考對象的擴展運算符),這是因為復合組件除了要求在子組件上執行setNativeProps意外,還要求子組件對觸摸事件進行處理,因此會傳遞多個props.