直接操作
サブツリー全体の再レンダリングをトリガーするためにstate/propsを使用せずに、コンポーネントを直接変更する必要がある場合があります。たとえば、ブラウザでReactを使用する場合、DOMノードを直接変更する必要がある場合があり、モバイルアプリのビューについても同じことが言えます。setNativeProps
は、DOMノードにプロパティを直接設定することに相当するReact Nativeです。
頻繁な再レンダリングがパフォーマンスのボトルネックになる場合は、setNativeProps
を使用してください!
直接操作は、頻繁に使用するツールではありません。通常は、コンポーネント階層のレンダリングと多数のビューの調整のオーバーヘッドを回避するために、連続的なアニメーションを作成する場合にのみ使用します。setNativeProps
は命令型であり、状態をReactコンポーネント内ではなくネイティブレイヤー(DOM、UIViewなど)に保存するため、コードの推論がより困難になります。
使用する前に、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
が利用できないと仮定しましょう。その制約で実装する1つの方法は、不透明度の値を状態に保存し、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
コンポーネントへの参照に存在するため、カスタムコンポーネントの参照をレンダリングする<View />
コンポーネントの1つに転送するだけで十分です。これは、カスタムコンポーネントでsetNativeProps
を呼び出すと、ラップされたView
コンポーネント自体でsetNativeProps
を呼び出した場合と同じ効果があることを意味します。
- TypeScript
- JavaScript
これで、TouchableOpacity
内でMyButton
を使用できるようになりました!
{...props}
を使用して、すべての子ビューにpropsを渡していることに気づいたかもしれません。これは、TouchableOpacity
が実際には複合コンポーネントであるためであり、子でsetNativeProps
に依存することに加えて、子がタッチ処理を実行する必要があるためです。これを行うために、TouchableOpacity
コンポーネントにコールバックするさまざまなpropsを渡します。対照的に、TouchableHighlight
はネイティブビューによってバックアップされており、setNativeProps
を実装することのみが必要です。
TextInput値を編集するためのsetNativeProps
setNativeProps
のもう1つの非常に一般的なユースケースは、TextInputの値を編集することです。bufferDelay
が低く、ユーザーが非常に速く入力すると、TextInputのcontrolled
プロパティが文字をドロップすることがあります。一部の開発者は、このプロパティを完全にスキップし、代わりに必要に応じてsetNativeProps
を使用してTextInput値を直接操作することを好みます。たとえば、次のコードは、ボタンをタップしたときに入力を編集する方法を示しています
- TypeScript
- JavaScript
clear
メソッドを使用してTextInput
をクリアし、同じアプローチを使用して現在の入力テキストをクリアできます。
render関数との競合の回避
render関数によっても管理されているプロパティを更新すると、コンポーネントが再レンダリングされ、そのプロパティが変更されるたびに、setNativeProps
から以前に設定された値は完全に無視され、上書きされるため、予期しない混乱を招くバグが発生する可能性があります。
setNativeProps & shouldComponentUpdate
shouldComponentUpdate
をインテリジェントに適用することで、変更されていないコンポーネントサブツリーの調整に関わる不必要なオーバーヘッドを回避できます。これにより、setNativeProps
の代わりにsetState
を使用するのに十分なパフォーマンスが得られる場合があります。
その他のネイティブメソッド
ここで説明するメソッドは、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()
の反対です。