状態に合わせてスタイルの上書き(オーバーライド)をしたいことはよくある。
1 2 3 4 5 6 7 8 9 |
const views = arr.map((v, i) => { const _style = StyleSheet.flatten([ styles.A, i % 2 == 0 && styles.B ]); return ( <View style={_style}>{v.name}</View> ); }); |
スタイル自体はStyleSheet.create
で定義してると思ってください。
通常[]
(配列)を使えばいいのですがちょっとハマったことがあったので、3つの方法と注意する点を書いておきます。
[] 配列による定義
公式ドキュメントにもありますし、「reactnative style override」で調べて出てくるページでもこれが紹介されています。
1 |
<View style={[styles.A, i % 2 == 0 && styles.B]}>{v.name}</View> |
[]
では配列の深さに関わらず最後の要素を優先して上書きします。
StyleSheet.flatten
という関数を使って実際に適応されるスタイルを見てみます。
1 2 3 4 5 6 7 8 |
console.log( StyleSheet.flatten([{ width: 48 }, [[{ width: 88 }], { width: 222 }]]) ); /* Object { "width": 222, } */ |
深さに関係なく最後に定義した要素が採用されることがわかります。
普通に使う分にはこれで問題ないです。
ただライブラリなどのスタイル指定するときには注意が必要です。
例えばReact Native ElementsのButtonでbuttonStyle
を設定することを考えます。
ここで[]を使った方法でborderRadius
を設定すると反映されません。
ソースを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
<View style={StyleSheet.flatten([ styles.container, { borderRadius: buttonStyle.borderRadius || styles.container.borderRadius, }, containerStyle, raised && !disabled && styles.raised(type), ])} > |
buttonStyle.borderRadius
で指定しているため、配列で渡すと認識されない。
つまりライブラリ側で配列で渡されることを想定していない場合に予期しないスタイルになってしまうことがあります。
対処方法
最も一般的な、フラットなオブジェクトで渡すことで問題は回避できます。
冒頭で書いたようにStyleSheet.flatten
を使うと簡単に平滑化できます。
1 2 3 4 |
const _style = StyleSheet.flatten([ styles.A, i % 2 == 0 && styles.B ]); |
条件指定がなければスプレット構文(...
)を使って結合すると簡潔です。
1 |
<View style={{ ...styles.A, ...styles.B }}>{v.name}</View> |
普段は気にする必要はないですが、こういうことがあるということを知っておくともしもの時に混乱しないで済むと思います。