TL;DR
TouchableHighlightは一つしか子要素を持てない。
バグが発生した状況
React Native(Expo使用)でUber eatsアプリのUIを再現しようと作業中。
商品をクリックした際のUIを模倣していたところ、どうやらタップした際に背景が明るくなるTouchableOpacityではなく、背景を暗く設定できるTouchableHighlightの方が適していることがわかった。
しかし、TouchableOpacityを利用していた場所をそのままTouchableHighlightにしたらエラー(React.Children.only expected to receive a single React element child.)が発生してしまった。
エラーが起きた時のコードの再現
const Product = (props: Props) => {
const _onPressButton = () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
};
return (
<TouchableHighlight
style={styles.container}
onPress={_onPressButton}
>
<View style={styles.img}>
<TouchableOpacity style={[styles.plusButton, styles.center]}>
<Text>+</Text>
</TouchableOpacity>
</View>
<View style={styles.description}>
<Text>¥228</Text>
<Text>美味しい水(500ml)</Text>
</View>
</TouchableHighlight>
);
};
解決方法
公式ドキュメントで調べたところ、TouchableHighlightは
TouchableHighlight must have one child (not zero or more than one). If you wish to have several child components, wrap them in a View.
と書かれており、TouchableHighlightの子要素は一つである必要があり、複数子要素を持ちたいときは<View>でラップする必要があった。
というわけでドキュメントの通りにViewでラップしたところ画面が正常に表示された。
const Product = (props: Props) => {
const _onPressButton = () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
};
return (
<TouchableHighlight
style={styles.container}
onPress={_onPressButton}
activeOpacity={1}
underlayColor={"#eee"}
>
<View>
<View style={styles.img}>
<TouchableOpacity style={[styles.plusButton, styles.center]}>
<Text>+</Text>
</TouchableOpacity>
</View>
<View style={styles.description}>
<Text>¥228</Text>
<Text>美味しい水(500ml)</Text>
</View>
</View>
</TouchableHighlight>
);
};
ちなみにTouchableHighlightのpropsであるactiveOpacityはunderlayColorと一緒に設定する必要がある。
正常に動作していることがわかる。
まとめ
TouchableOpacityとTouchableHighlightは持つことのできる子要素の数が異なる。