🐮

React Native PaperでStyle Propsを使えるようにする

2021/11/11に公開

React Native PaperにStyled Systemを導入してStyle Propsが使えるようにしてみました。

React Native Paperとは?

React Native PaperはReact Native / Web用に開発されたUIライブラリーです。デザインはMaterial Designに準拠しています。

https://callstack.github.io/react-native-paper/

Style Propsが使いたい

React Native Paperは使い勝手の良いUIライブラリーなのですが「このボタンのレイアウトを少しカスタマイズしたい」という場面がでてきた時には 「style」プロパティーで「fontSize」や「padding」などの値を直接指定する必要があります。

HomeScreen.js
const HomeScreen = () => (
    <Card
        style={{
          backgroundColor: 'red',
          padding: '4px',
          borderWidth: '1px',
          margin: '4px',
        }}
    />
);

React Native Paperのデザイン・システムに従ってカスタマイズしたい

またReact Native PaperのUIコンポーネントで使用されている「padding」や 「fontSize」などの値はエクスポートされておらず、同じ値をカスタムUIで使用する場合はソースコードを参照してコピペする必要があります。

デザイン・システムに従って整合性を保ちながらUIをカスタマイズするのがなかなか大変ですね。

最近ではNative BaseなどStyle Propsに対応することでこうした問題に対応したUIライブラリも登場してきています。

https://note.com/umotion/n/n0fb7ff377b3f

だがReact Native Paperは使い続けたい

ただ、もともとReact Native Paperを使っていたプロダクトではUIコンポーネントのデザインが微妙に変わってしまうなど入れ替えが難しいケースもあります。

そんなわけで、React Native PaperをStyle Propsに対応させてみよう

Native BaseはStyle Propsの実装にStyled Systemという外部のライブラリを使用しています。Styled Systemは、ReactコンポーネントにStyle Propsを追加できる汎用のライブラリです。

https://styled-system.com/

それなら、React Native PaperにもStyled Systemを導入すれば良いのでは?ということで試してみました。

CSS-in-JSライブラリstyled-componentsを導入

Styled Systemが提供する Style Props を既存のコンポーネントで使えるようにするには、styled-component などのスタイル・ライブラリを使用します。

https://styled-components.com/docs/basics#react-native

Styled SystemをReact Native Paperのコンポーネントに適用

styled-componentとstyled-systemを使ったコードはこんな感じになります。

ReactNativeStyledPaper.js
import styled from 'styled-components/native';
import { color, border, padding, margin } from 'styled-system';

import { Card as _Card_ } from 'react-native-paper';
import { ScrollView as _ScrollView_ } from 'react-native';

export const Card = styled(_Card_)(color, border, padding, margin);
export const ScrollView = styled(_ScrollView_)(color, border, padding, margin);

Style Propsに対応したReact Native Paperコンポーネント

実際に使ってみましょう.

HomeScreen.tsx
const HomeScreen = () => (
  <Card
    backgroundColor='red'
    padding={2}
    borderWidth={1}
    margin={2}
  />
);

スタイル属性が直接プロパティーとして記述できるのでコードがすっきりしました。

Styled SystemのテーマにReact Native Paperのテーマの値を適用する

スタイルで直値を使わないメリット

Styled Systemを導入するメリットとしてStyle Propsが使えるようになる他に「borderWidth」「padding」 などを直値ではなくてテーマのキーで指定できるようになることがあります。たとえば「fontSize」には下記のような値が『テーマ』として予め定義されています。

fontSizes: [12, 14, 16, 20, 24, 32]

Styled SystemのStyle Propsでは、フォント・サイズを直接指定するのではなくてインデックスを使用します。

<SomeComponent fontSize={3} /> // ← fontSizes[3] = 20 が指定される

これによって使用する値が常にデザイン・システムに従うようになります。同じアプリケーションなのにコンポーネントごとにメインのフォントサイズが微妙に異なるような状態を避けることができます。

テーマの適用

Styled Systemを導入するとフォント・サイズやパディングなどのテーマに標準の値が使われます。チェックしたところReact Native Paperの値とほとんど一緒でしたが、微調整が必要でした。

https://styled-system.com/theme-specification/

Styled SystemのTheme機能を使って修正します。

import { DefaultTheme as __DefaultTheme } from 'react-native-paper';

export const DefaultTheme = {
  fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96, 128],
  space: [0, 4, 8, 16, 32, 64, 128, 256],
  colors: __DefaultTheme.colors,
  fonts: __DefaultTheme.fonts,
};

フォントサイズ

React Native Paperの componentsのコードをチェックして利用されているfontSizeを拾い上げていきます(地道)。Titleコンポーネントに使われていた「fontSize:20」などを足していきます。

fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96, 128]

レイアウト・パラメータ(padding・margin...)

レイアウト・パラメータも同様にコンポーネントで利用されていた値を拾っていきました。

space: [0, 4, 8, 16, 32, 64, 128, 256]

Styled SystemのThemeProviderにテーマをセット

App.tsx

<StyledComponentsThemeProvider
  theme={DefaultTheme}
>
  <App />
</StyledComponentsThemeProvider>

アプリケーションをStyled SystemのThemeProviderで囲んで、themeに先程作成したDefaultThemeをセットします。これで <App /> 内のStyled Systemベースのコンポーネントでテーマの値を参照できます。

Styleの値を直接参照する場合

import css from '@styled-system/css';

console.log(css({
  fontSize: 0
)()); // ⇒ 12

条件によって値を変える場合など、どうしても「style」プロパティーに値を設定したい場合もありますね。Styled Systemはcssというメソッドを用意しています。Style Propsと同じ { fontSize: 0 } などの値を引数として渡すとテーマに従って値を返してくれます。

まとめ

Styled Systemを使ってReact Native PaperでUtility Propsを使えるようにする方法を紹介しました。

既存のコンポーネントをちょっとだけ修正する際などにstyleに直接フォントサイズを設定せずにReact Native Paperのデザイン・システムに従うことができるようになりました。

Style Propsは導入したいけどいきなりライブラリを入れ替えるのは難しいというプロジェクトで、ぜひ一度検討してみてください。

(ちなみに、今回紹介したNative BaseもHStackコンポーネントやVStackコンポーネント、グリッドを作成しやすいレイアウト指定など便利な機能が沢山あり、部分的に混ぜて使うことも可能ですので併用もオススメです)

U-motionとは?

U-motionは牛の首につけたセンサーを使って活動内容を記録、AIの力で健康状態を解析して畜産農家さんをサポートするモニタリング・システムです。

https://www.desamis.co.jp/product/

https://www.youtube.com/watch?v=RBw1PMwow-Y

Discussion