はじめに
React Nativeでアプリを作り始めると、まず悩むのがUIコンポーネントです。ボタンひとつ、リストひとつ取っても、iOSとAndroidで見た目を揃えるにはスタイルを自分で書き込む必要がありますし、それをWeb版にも展開しようとすると、さらに手間が増えていきます。
React Native Elementsは、この「プラットフォームごとにUIを作り直す」手間を減らすために作られたコンポーネントライブラリです。ButtonやCard、ListItemといった定番パーツがあらかじめ用意されていて、テーマ機能で色やサイズを一箇所から管理できます。しかもReact Native Webを介せば、同じコンポーネントをブラウザ上でも動かせるとうたっています。
なお本記事では、他の記事で行っているようなLiveCodesの実行可能サンプルは掲載していません。理由は後述しますが、React Native Elementsは前提としてExpoやReact Native CLI、あるいはWebpackのモジュールエイリアス設定を必要とするため、ブラウザの単一ページ上で完結する形にできないためです。その代わり、実際のプロジェクトにそのまま貼り付けられるコード例を中心に解説します。
React Native Elementsとは
React Native Elementsは、iOS・Android・Webの3プラットフォームに対応したクロスプラットフォームUIツールキットです。GitHub上で25,000以上のスターを獲得しており、React Nativeエコシステムの中でも定番のUIライブラリのひとつとして使われ続けています。
現在のパッケージ構成はバージョン4系への移行を経て、@rneui/base(コアコンポーネント)と@rneui/themed(テーマ機能つきラッパー)の2パッケージに分かれています。旧パッケージ名のreact-native-elementsはメンテナンスが止まっており、新規プロジェクトでは@rneui系を使うのが公式の推奨です。
主な特徴
- 豊富な定番コンポーネント - Button、Card、Avatar、Badge、ListItem、Input、SearchBar、Overlay、Rating、Sliderなど、モバイルUIでよく使う部品がひととおり揃っています
- 統一されたテーマシステム -
createThemeとThemeProviderを使うことで、色・余白・コンポーネントごとのデフォルトPropsをアプリ全体で一元管理できます。light/darkモードの切り替えにも対応しています - TypeScript対応 - 型定義が同梱されており、Props補完が効いた状態でコンポーネントを組み立てられます
- React Native Webとの連携 - React Native CLIやExpoだけでなく、Create React Appベースのプロジェクトでも同じコンポーネントを使える設計になっています
インストール
Expoプロジェクトの場合は、以下のコマンドで導入します。
npx expo install @rneui/themed @rneui/base
React Native CLIの場合は次のとおりです。
npm install @rneui/themed @rneui/base
Web版(React Native Web経由)を使う場合は、追加でreact-native-webと、アイコンを使うならreact-native-vector-iconsも必要になります。
npm install react-native-web react-native-vector-icons
このWeb対応が、React Native Elementsを「モバイル専用ではない」ライブラリたらしめている部分です。ただし実際に動かすには、Webpackなどのバンドラでreact-nativeをreact-native-webにエイリアスする設定が必要で、この設定はプロジェクトのビルド構成に依存します。そのため、ブラウザ単体で完結するインタラクティブなサンプル(LiveCodesのようなプレイグラウンド)を本記事に埋め込むことができません。動かないサンプルを無理に置くよりは、実際のプロジェクトにそのまま持っていけるコードを示す方が有用だと考え、本記事ではその方針を取っています。
基本的な使い方
もっとも基本的なコンポーネントはButtonです。@rneui/themedからButtonをインポートし、titlePropsに文字列を渡すだけで、プラットフォームに合わせたスタイルのボタンが表示されます。
import { Button } from '@rneui/themed';
export default function App() {
return (
<Button
title="送信する"
type="solid"
size="lg"
onPress={() => console.log('pressed')}
/>
);
}
typeプロパティで見た目をsolid(塗りつぶし)、outline(枠線のみ)、clear(背景なし)から選べます。loadingをtrueにすればローディングスピナーに切り替わり、非同期処理中のフィードバックも数行で実装できます。
<Button title="読み込み中" loading={true} />
<Button title="無効化" disabled={true} />
実践的なユースケース
テーマを一元管理する
アプリ全体で色やコンポーネントのデフォルト値を揃えたいときは、createThemeでテーマオブジェクトを作り、ThemeProviderでアプリのルートを包みます。これによりコンポーネントごとに毎回同じPropsを書く必要がなくなり、デザインの変更も1箇所で完結します。
import { ThemeProvider, createTheme, Button } from '@rneui/themed';
const theme = createTheme({
lightColors: {
primary: '#2563eb',
},
darkColors: {
primary: '#60a5fa',
},
mode: 'light',
components: {
Button: {
raised: true,
},
},
});
export default function App() {
return (
<ThemeProvider theme={theme}>
<Button title="テーマ適用済みボタン" />
</ThemeProvider>
);
}
modeを'dark'に切り替えると、darkColors側の値が自動的に反映されます。OSのダークモード設定に連動させたい場合は、useColorSchemeフックの値をここに渡す形で組み合わせるのが定番のパターンです。
リスト表示をListItemで組み立てる
連絡先一覧や設定画面のようなリストUIは、ListItemとその子コンポーネント(ListItem.Content、ListItem.Titleなど)を組み合わせることで、Flexboxのレイアウトを自分で書かずに実装できます。
import { ListItem, Avatar } from '@rneui/themed';
const users = [
{ name: '田中太郎', role: 'エンジニア' },
{ name: '佐藤花子', role: 'デザイナー' },
];
export default function UserList() {
return (
<>
{users.map((user, i) => (
<ListItem key={i} bottomDivider>
<Avatar rounded title={user.name[0]} />
<ListItem.Content>
<ListItem.Title>{user.name}</ListItem.Title>
<ListItem.Subtitle>{user.role}</ListItem.Subtitle>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
))}
</>
);
}
ListItem.Chevronを付けるだけで右端に矢印アイコンが表示され、タップで詳細画面に遷移するようなナビゲーションUIを、レイアウト崩れの心配なく組み立てられます。
入力フォームとバリデーション表示
Inputコンポーネントは、ラベル・エラーメッセージ・アイコンをまとめて扱えるため、フォーム画面を素早く作るのに向いています。
import { useState } from 'react';
import { Input, Button } from '@rneui/themed';
export default function SignupForm() {
const [email, setEmail] = useState('');
const isValid = /\S+@\S+\.\S+/.test(email);
return (
<>
<Input
label="メールアドレス"
value={email}
onChangeText={setEmail}
errorMessage={
email.length > 0 && !isValid ? '正しい形式で入力してください' : ''
}
/>
<Button title="登録" disabled={!isValid} />
</>
);
}
errorMessageに空文字以外を渡すと、入力欄の下に赤字でエラーが表示される仕組みです。バリデーション結果をstateで持ち、errorMessageに渡すだけで済むため、エラー表示用のスタイルを個別に書く必要がありません。
まとめ
React Native Elementsは、Button・Card・ListItem・Inputといったモバイルアプリの定番UIを、テーマで統一しながら素早く組み立てられるライブラリです。@rneui/baseと@rneui/themedへの移行によりパッケージ構成が整理され、TypeScriptの型サポートも受けられるようになりました。
React Native Webを使えばWeb版への展開も視野に入りますが、実際に動かすにはバンドラ側のエイリアス設定が必要になるため、「Reactの延長でそのままブラウザに持っていける」というよりは「React Nativeのコンポーネント資産をWebにも広げられる」と捉えておくのが実態に近いでしょう。まずはExpoやReact Native CLIのプロジェクトにインストールして、Button・ListItem・Inputあたりから触ってみることをおすすめします。