はじめに
React Nativeでモバイルアプリを作っていると、スタイリングが面倒だと感じることってありませんか。StyleSheetで書くのも悪くないんですが、Webで慣れたTailwind CSSのクラス指定がそのまま使えたらなぁ、と思うことは正直多いです。
そんな中、Unistylesの開発チームが新たにリリースした「Uniwind」というライブラリがかなり良さそうなので紹介します。これ、React Native向けの高速なTailwind CSSバインディングで、パフォーマンスにこだわった設計になっているんですよね。
Uniwindとは
UniwindはReact NativeアプリでTailwind CSSのクラス名をそのまま使えるようにするライブラリです。「className」プロパティをReact Nativeのコンポーネントに追加してくれるので、Webでの開発体験がそのままモバイルでも使えます。
開発元はUnistylesというReact Native向けスタイリングライブラリで実績のあるチーム。パフォーマンスに対する知見が豊富で、Uniwindもその経験を活かした設計になっています。
特徴・メリット
ビルド時にスタイルを計算
個人的にこれが一番のポイントだと思っています。Uniwindはスタイルをビルド時に計算するので、ランタイムでのオーバーヘッドが最小限になります。似たようなライブラリはいくつかありますが、パフォーマンス面ではかなり優位性がありそうです。
Tailwind CSSクラスがそのまま使える
Web開発でTailwind CSSに慣れている人なら、学習コストはほぼゼロ。flex、justify-center、p-4といったお馴染みのクラス名がそのまま動きます。
<View className="flex-1 justify-center items-center bg-gray-100">
<Text className="text-xl font-bold text-gray-800">Hello Uniwind</Text>
</View>
ダークモード対応
テーマ切り替えにも対応していて、ダークモードの実装が楽になります。カスタムテーマも作れるので、アプリのブランドカラーに合わせた設定も可能です。
疑似クラスのサポート
focus、active、disabledといった状態に応じたスタイル指定ができます。これ、意外と対応していないライブラリも多いので、ちゃんとサポートしているのは嬉しいポイントですね。
レスポンシブデザイン対応
メディアクエリによるレスポンシブ対応もサポート。タブレットとスマホで異なるレイアウトを組むときに便利です。
インストール方法
bunを使う場合はこれだけです。
bun add uniwind tailwindcss
npmやyarnでも同様にインストールできます。
npm install uniwind tailwindcss
# または
yarn add uniwind tailwindcss
インストール後は公式ドキュメントのQuickstartに従って設定を進めていきます。TypeScriptで書かれているので、型のサポートもバッチリです。
基本的な使い方
セットアップ
まずtailwind.config.jsを作成して、Tailwindの設定を行います。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./app/**/*.{js,jsx,ts,tsx}', './components/**/*.{js,jsx,ts,tsx}'],
theme: {
extend: {},
},
plugins: [],
}
コンポーネントでの使用
React NativeのコンポーネントにclassNameを追加するには、withUniwindというHOCを使います。
import { View, Text } from 'react-native'
import { withUniwind } from 'uniwind'
const StyledView = withUniwind(View)
const StyledText = withUniwind(Text)
export function Card() {
return (
<StyledView className="p-4 bg-white rounded-lg shadow-md">
<StyledText className="text-lg font-semibold text-gray-900">
カードタイトル
</StyledText>
<StyledText className="mt-2 text-gray-600">
カードの説明文がここに入ります。
</StyledText>
</StyledView>
)
}
useUniwindフック
現在のテーマにアクセスしたり、テーマを切り替えたりするときはuseUniwindフックが使えます。
import { useUniwind } from 'uniwind'
export function ThemeToggle() {
const { theme, setTheme } = useUniwind()
return (
<Button
onPress={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
title={`現在: ${theme}モード`}
/>
)
}
useResolveClassNames
クラス名をReact Nativeのスタイルオブジェクトに変換したいケースでは、useResolveClassNamesが便利です。
import { useResolveClassNames } from 'uniwind'
export function CustomComponent() {
const styles = useResolveClassNames('p-4 bg-blue-500 rounded-xl')
return <View style={styles}>{/* ... */}</View>
}
実践的なユースケース
ボタンコンポーネント
実際のプロジェクトで使いそうなボタンコンポーネントを作ってみます。
import { Pressable, Text } from 'react-native'
import { withUniwind } from 'uniwind'
const StyledPressable = withUniwind(Pressable)
const StyledText = withUniwind(Text)
type ButtonProps = {
title: string
variant?: 'primary' | 'secondary'
disabled?: boolean
onPress: () => void
}
export function Button({ title, variant = 'primary', disabled, onPress }: ButtonProps) {
const baseClasses = 'px-6 py-3 rounded-lg active:opacity-80'
const variantClasses = variant === 'primary'
? 'bg-blue-600 disabled:bg-blue-300'
: 'bg-gray-200 disabled:bg-gray-100'
const textClasses = variant === 'primary'
? 'text-white font-semibold'
: 'text-gray-800 font-medium'
return (
<StyledPressable
className={`${baseClasses} ${variantClasses}`}
disabled={disabled}
onPress={onPress}
>
<StyledText className={textClasses}>{title}</StyledText>
</StyledPressable>
)
}
リストアイテム
FlatListと組み合わせて使うリストアイテムの例です。
import { View, Text, Image } from 'react-native'
import { withUniwind } from 'uniwind'
const StyledView = withUniwind(View)
const StyledText = withUniwind(Text)
const StyledImage = withUniwind(Image)
type ItemProps = {
title: string
description: string
imageUrl: string
}
export function ListItem({ title, description, imageUrl }: ItemProps) {
return (
<StyledView className="flex-row p-4 bg-white border-b border-gray-200">
<StyledImage
className="w-16 h-16 rounded-full"
source={{ uri: imageUrl }}
/>
<StyledView className="ml-4 flex-1 justify-center">
<StyledText className="text-base font-bold text-gray-900">
{title}
</StyledText>
<StyledText className="mt-1 text-sm text-gray-500">
{description}
</StyledText>
</StyledView>
</StyledView>
)
}
まとめ
UniwindはReact NativeでTailwind CSSを使いたい人にとって、かなり有力な選択肢になりそうです。
ポイントをまとめると:
- ビルド時にスタイル計算するのでパフォーマンスが良い
- Tailwind CSSのクラス名がそのまま使える
- ダークモードやレスポンシブ対応もサポート
- Unistylesチームの実績があり信頼性が高い
NativeWindからの移行ガイドも公式ドキュメントに用意されているので、既存プロジェクトからの乗り換えも検討しやすいと思います。
React Nativeのスタイリングで悩んでいる人は、一度試してみる価値はありますね。個人的にはビルド時計算というアプローチが気に入っています。ランタイムのパフォーマンスを気にしなくていいのは、プロダクションで使うことを考えるとかなり大きなメリットです。
公式ドキュメント: https://docs.uniwind.dev