はじめに
今回は、react nativeでTouchableOpacity
とPressable
のネストした時の挙動、およびそれらを組み合わせた時の挙動等をざっと羅列していきます。
環境
- react native 0.73.6
- expo 50.0.0
- IOSシミュレータ ios 17.5
本題
TouchableOpacityのネスト
<TouchableOpacity onPress={() => console.log('t 1')}>
<TouchableOpacity onPress={() => console.log('t 2')}>
<View style={style.rect} />
</TouchableOpacity>
</TouchableOpacity>
結果 : t 2
Pressableのネスト
<Pressable onPress={() => console.log('p 1')}>
<Pressable onPress={() => console.log('p 2')}>
<View style={style.rect} />
</Pressable>
</Pressable>
結果 : p 2
単純なネストの場合は、より前面にあるタッチ可能コンポーネントのonPressが発火するようですね。
Pressable in TouchableOpacity
<TouchableOpacity onPress={() => console.log('t 1')}>
<Pressable onPress={() => console.log('p 2')}>
<View style={style.rect} />
</Pressable>
</TouchableOpacity>
結果 : t 1
TouchableOpacity in Pressable
<Pressable onPress={() => console.log('p 1')}>
<TouchableOpacity onPress={() => console.log('t 2')}>
<View style={style.rect} />
</TouchableOpacity>
</Pressable>
結果 : p 2 t 2
これが謎です。Pressable
のonPress
が発火した後に、TouchableOpacity
のonPress
が発火しています。
伝播とも異なり、親のonPress→子のonPressの順で発火しているのも直感に反します。
それぞれの実装からくる挙動なのだとは思いますが...
Pressable in Pressable in TouchableOpacity
<Pressable onPress={() => console.log('p 1')}>
<Pressable onPress={() => console.log('p 2')}>
<TouchableOpacity onPress={() => console.log('t 1')}>
<View style={style.rect} />
</TouchableOpacity>
</Pressable>
</Pressable>
結果 : p 2 t 1
TouchableOpacity in Pressable in TouchableOpacity
<TouchableOpacity onPress={() => console.log('t 1')}>
<Pressable onPress={() => console.log('p 1')}>
<TouchableOpacity onPress={() => console.log('t 2')}>
<View style={style.rect} />
</TouchableOpacity>
</Pressable>
</TouchableOpacity>
結果 : p 1 t 2
これも謎です。Pressable in TouchableOpacityの挙動とはまた違う挙動を示しています
position: absoluteを使ったPressable
<Pressable
onPress={() => console.log('p 1')}
style={{ position: 'relative' }}
>
<Pressable
style={{ ...style.rect, position: 'absolute' }}
onPress={() => console.log('p 2 ')}
/>
<View style={style.rect} />
<Pressable
style={{ ...style.rect, position: 'absolute' }}
onPress={() => console.log('p 3')}
/>
</Pressable>
結果 : p 3
position: absoluteを使ったPressable Index設定あり
<Pressable
onPress={() => console.log('p 1')}
style={{ position: 'relative' }}
>
<Pressable
style={{ ...style.rect, position: 'absolute', zIndex: 2 }}
onPress={() => console.log('p 2 z 2')}
/>
<View style={style.rect} />
<Pressable
style={{ ...style.rect, position: 'absolute', zIndex: 1 }}
onPress={() => console.log('p 3 z 1')}
/>
</Pressable>
結果 : p 2 z 2
position: absoluteを使った TouchableOpacity in Pressable
<View style={style.rect}>
<Pressable
onPress={() => console.log('p 1')}
style={{ position: 'relative' }}
>
<Pressable
style={{ ...style.rect, position: 'absolute', zIndex: 1 }}
onPress={() => console.log('p 2 z 1')}
/>
<TouchableOpacity
style={{ ...style.rect, position: 'absolute' }}
onPress={() => console.log('t 1 z 0')}
/>
</Pressable>
</View>;
結果 : p 2 z 1
position: absoluteを使った TouchableOpacity in Pressable (同Index)
<View style={style.rect}>
<Pressable
onPress={() => console.log('p 1')}
style={{ position: 'relative' }}
>
<Pressable
style={{ ...style.rect, position: 'absolute', zIndex: 1 }}
onPress={() => console.log('p 2 z 1')}
/>
<TouchableOpacity
style={{ ...style.rect, position: 'absolute', zIndex: 1 }}
onPress={() => console.log('t 1 z 1')}
/>
</Pressable>
</View>;
結果 : p 2 z 1
position: absoluteを使った TouchableOpacity in Pressable (異なるIndex)
<View style={style.rect}>
<Pressable
onPress={() => console.log('p 1')}
style={{ position: 'relative' }}
>
<Pressable
style={{ ...style.rect, position: 'absolute', zIndex: 1 }}
onPress={() => console.log('p 2 z 1')}
/>
<TouchableOpacity
style={{ ...style.rect, position: 'absolute', zIndex: 2 }}
onPress={() => console.log('t 1 z 2')}
/>
</Pressable>
</View>;
結果 : p 2 z 1
まとめ
TouchableOpacity
とPressable
のネストした時の挙動、およびそれらを組み合わせた時の挙動についてざっとまとめてみました。
ほとんどは直感通りの挙動ですが、TouchableOpacity in Pressableのように特殊な挙動を示すケースもあるようです。
TouchableOpacity
とPressable
を組み合わせることで、直感に反する挙動が発生しているように見受けられるので、プロジェクトごとにどちらを使用するか決めておいた方が良いかもしれません。
最後まで読んでいただき、ありがとうございました。