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
は持つことのできる子要素の数が異なる。