直接操作
有時必須直接變更組件,而無需使用狀態/props 來觸發整個子樹的重新渲染。例如,在瀏覽器中使用 React 時,有時您需要直接修改 DOM 節點,行動應用程式中的視圖也是如此。 setNativeProps
是 React Native 中相當於直接設定 DOM 節點屬性的方法。
當頻繁的重新渲染造成效能瓶頸時,請使用 setNativeProps
!
直接操作不會是您經常使用的工具。您通常只會在建立連續動畫時使用它,以避免渲染組件層級和協調許多視圖的開銷。 setNativeProps
是命令式的,並將狀態儲存在原生層(DOM、UIView 等)而不是您的 React 組件中,這會使您的程式碼更難以理解。
在使用它之前,請嘗試使用 setState
和 shouldComponentUpdate
來解決您的問題。
搭配 TouchableOpacity 使用 setNativeProps
TouchableOpacity 在內部使用 setNativeProps
來更新其子組件的不透明度
const viewRef = useRef<View>();
const setOpacityTo = useCallback(value => {
// Redacted: animation related code
viewRef.current.setNativeProps({
opacity: value,
});
}, []);
這讓我們可以編寫以下程式碼,並知道子組件的不透明度會隨著點擊而更新,而子組件無需知道這一點或需要對其實現進行任何變更
<TouchableOpacity onPress={handlePress}>
<View>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
讓我們想像一下,如果 setNativeProps
不可用。我們可以使用該約束條件實現它的一種方法是將不透明度值儲存在狀態中,然後在每次觸發 onPress
時更新該值
const [buttonOpacity, setButtonOpacity] = useState(1);
return (
<TouchableOpacity
onPressIn={() => setButtonOpacity(0.5)}
onPressOut={() => setButtonOpacity(1)}>
<View style={{opacity: buttonOpacity}}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
);
與原始範例相比,這在計算上是密集型的 - 每次不透明度變更時,React 都需要重新渲染組件層級,即使視圖及其子組件的其他屬性沒有變更也是如此。通常,這種開銷不是問題,但在執行連續動畫和回應手勢時,明智地最佳化您的組件可以提高動畫的逼真度。
如果您查看 NativeMethodsMixin 中 setNativeProps
的實現,您會注意到它是 RCTUIManager.updateView
的包裝器 - 這與重新渲染產生的函數呼叫完全相同 - 請參閱 ReactNativeBaseComponent 中的 receiveComponent。
複合組件和 setNativeProps
複合組件沒有原生視圖的支持,因此您無法在其上呼叫 setNativeProps
。請考慮以下範例
- TypeScript
- JavaScript
如果您執行此程式碼,您會立即看到此錯誤:Touchable child must either be native or forward setNativeProps to a native component
。發生這種情況是因為 MyButton
並非直接由應設定其不透明度的原生視圖支持。您可以這樣想:如果您使用 createReactClass
定義組件,您不會期望能夠在其上設定 style prop 並使其運作 - 您需要將 style prop 傳遞給子組件,除非您正在包裝原生組件。同樣地,我們將把 setNativeProps
轉發到原生支持的子組件。
將 setNativeProps 轉發到子組件
由於 setNativeProps
方法存在於任何 View
組件的 ref 上,因此將自訂組件上的 ref 轉發到它渲染的其中一個 <View />
組件就足夠了。這表示在自訂組件上呼叫 setNativeProps
將具有與您在包裝的 View
組件本身上呼叫 setNativeProps
相同的效果。
- TypeScript
- JavaScript
您現在可以在 TouchableOpacity
內使用 MyButton
!
您可能已經注意到,我們使用 {...props}
將所有 props 傳遞給子視圖。這樣做的原因是 TouchableOpacity
實際上是一個複合組件,因此除了依賴其子組件上的 setNativeProps
之外,它還要求子組件執行觸控處理。為此,它傳遞了各種 props,這些 props 回呼到 TouchableOpacity
組件。相反地,TouchableHighlight
由原生視圖支持,並且僅要求我們實現 setNativeProps
。
使用 setNativeProps 編輯 TextInput 值
setNativeProps
的另一個非常常見的用例是編輯 TextInput 的值。當 bufferDelay
較低且使用者輸入速度非常快時,TextInput 的 controlled
prop 有時可能會遺漏字元。有些開發人員更喜歡完全跳過此 prop,而是在必要時使用 setNativeProps
直接操作 TextInput 值。例如,以下程式碼示範了在您點擊按鈕時編輯輸入
- TypeScript
- JavaScript
您可以使用 clear
方法來清除 TextInput
,這會使用相同的方法清除目前的輸入文字。
避免與 render 函數衝突
如果您更新的屬性也由 render 函數管理,您最終可能會遇到一些不可預測且令人困惑的錯誤,因為每當組件重新渲染且該屬性變更時,先前從 setNativeProps
設定的任何值都將被完全忽略和覆寫。
setNativeProps & shouldComponentUpdate
透過智慧地應用 shouldComponentUpdate
,您可以避免協調未變更的組件子樹所涉及的不必要開銷,達到可以使用 setState
而不是 setNativeProps
的程度。
其他原生方法
此處描述的方法在 React Native 提供的預設組件的大部分中都可用。但是請注意,它們不適用於非原生視圖直接支持的複合組件。這通常包括您自己在應用程式中定義的大多數組件。
measure(callback)
判斷給定視圖在螢幕上的位置、寬度和高度(在視口中),並透過非同步回呼傳回這些值。如果成功,則將使用以下引數呼叫回呼
- x
- y
- 寬度
- 高度
- pageX
- pageY
請注意,這些測量值在原生中完成渲染後才可用。如果您需要盡快取得測量值,並且不需要 pageX
和 pageY
,請考慮改用 onLayout
屬性。
此外,measure()
傳回的寬度和高度是組件在視口中的寬度和高度。如果您需要組件的實際大小,請考慮改用 onLayout
屬性。
measureInWindow(callback)
判斷給定視圖在視窗中的位置,並透過非同步回呼傳回這些值。如果 React 根視圖嵌入在另一個原生視圖中,這將為您提供絕對座標。如果成功,則將使用以下引數呼叫回呼
- x
- y
- 寬度
- 高度
measureLayout(relativeToNativeComponentRef, onSuccess, onFail)
與 measure()
類似,但相對於祖先視圖(使用 relativeToNativeComponentRef
參考指定)測量視圖。這表示傳回的座標相對於祖先視圖的原點 x
、y
。
此方法也可以使用 relativeToNativeNode
處理常式(而不是參考)呼叫,但此變體在新架構中已過時。
- TypeScript
- JavaScript
focus()
請求給定輸入或視圖的焦點。觸發的確切行為將取決於平台和視圖類型。
blur()
移除輸入或視圖的焦點。這與 focus()
相反。