ClaudeExpo2026/02/03 14:15

Building high-quality UIs with Expo and NativeWind

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

claudejamodel: claude-sonnet-4-20250514

ExpoとNativeWindを使った高品質UIの構築

Key Points

  • Figmaを使わずコード内で直接UI設計
  • NativeWindのvarsによる効率的なテーマ管理
  • 再利用可能なコンポーネントライブラリの構築

Summary

Expo、NativeWind、Reanimatedを組み合わせてReact Nativeアプリを効率的に開発する手法を紹介。Figmaを使わずにコード内で直接デザインし、再利用可能なコンポーネントとテーマシステムを構築する方法を解説。

Key Points

  • 再利用可能なコンポーネント設計

    • 柔軟なHeaderコンポーネントの実装
    • アニメーション付きタブナビゲーション
    • マルチステップフォームとオンボーディングフロー
    • フィルターやフォーム用のChipコンポーネント
  • NativeWindによるテーマシステム

    • CSS変数(vars)を使用したテーマ切り替え
    • ライト・ダークモードの一元管理
    • デザインシステムの核としてのテーマ実装
  • 開発効率の向上

    • Expo Go のライブプレビューでリアルタイム開発
    • テンプレートベースの開発アプローチ
    • Reanimatedによるアニメーション実装

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

claudejamodel: claude-sonnet-4-20250514

ExpoとNativeWindで高品質なUIを構築する

ExpoとNativeWindで高品質なUIを構築する

開発 • React Native • 2026年2月3日 • 3分で読める

Thomino ゲスト著者

Expo、NativeWind、Reanimatedを使用してReact Nativeアプリを直接コードでデザインする方法を学びます。再利用可能なコンポーネントを構築し、テーマを実装し、Figmaをスキップしましょう。

これはThominoからのゲスト投稿です - 彼はNative Templatesの作成者であり、Xでフォローする価値のある人物です。

私はIE6の時代からWebを構築してきました。ボックスシャドウにスライスした画像を使用し、角丸に透明GIFを使用し、構造に入れ子のテーブルを使用していたことを覚えています。それらはフロントエンド開発の「暗黒時代」でした。

幸い、時代は変わりました。Expo、NativeWind、Reanimatedの組み合わせにより、アプリのデザインは簡単になりました。実際、私はもうFigmaを使用していません。Expo Goのライブプレビューでコード内で直接デザインしています。

私のワークフローで使用する再利用可能なコンポーネントを使って、どのようにアプリを構築するかをお見せしましょう。これらのコンポーネントにより、エディタで直接デザインできます。また、テーマの処理方法とアニメーション付きテーマトグルの構築方法についても説明します。

再利用可能なコンポーネント

各アプリは異なりますが、ほとんどのアプリは多くの画面、フロー、コンポーネントを共有しています。そのため、私のニーズに応じて新しいプロジェクトのベースとして常に使用できるテンプレートを構築することにしました。

これを効果的に行うための鍵は、特定のアプリに応じて簡単にスタイリングできる再利用可能なコンポーネントを作成することでした。NativeTemplatesで実装したいくつかの例を以下に示します。

NativeWindで柔軟なヘッダーコンポーネントを構築する

間違いなく最も重要で基本的なものです。ヘッダーコンポーネントを柔軟で、ニーズに応じて簡単に調整できるようにすることが非常に重要でした。

import React from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { useThemeColors } from "app/contexts/ThemeColors";
import { Link, router } from "expo-router";
import Icon, { IconName } from "./Icon";
import { useSafeAreaInsets } from "react-native-safe-area-context";

type HeaderProps = {
  title: string,
  showBackButton?: boolean,
  rightComponents?: React.ReactNode[],
};

const Header: React.FC<HeaderProps> = ({
  title,
  showBackButton = false,
  rightComponents = [],
}) => {
  const colors = useThemeColors();
  const insets = useSafeAreaInsets();

  const handleBackPress = () => {
    router.back();
  };

  return (
    <View
      style={{ paddingTop: insets.top }}
      className="w-full pb-2 flex-row justify-between px-6 bg-background"
    >
      <View className="flex-row items-center flex-1">
        {showBackButton && (
          <TouchableOpacity
            onPress={handleBackPress}
            className="mr-4 py-4"
          >
            <Icon name="ArrowLeft" size={24} color={colors.icon} />
          </TouchableOpacity>
        )}
        <View className="py-4">
          <Text className="text-lg font-bold" style={{ color: colors.text }}>
            {title}
          </Text>
        </View>
      </View>
      {rightComponents.length > 0 && (
        <View className="flex-row items-center justify-end flex-1">
          {rightComponents.map((component, index) => (
            <View key={index} className="ml-6">
              {component}
            </View>
          ))}
        </View>
      )}
    </View>
  );
};

export default Header;
// タイトル付きの基本ヘッダー
<Header title="Home" />

// 戻るボタン付きヘッダー
<Header title="Details" showBackButton />

// アクションアイコン付きヘッダー
<Header
  title="Messages"
  rightComponents={[
    <HeaderIcon key="search" icon="Search" href="/search" />,
    <HeaderIcon key="settings" icon="Settings" href="/settings" />
  ]}
/>

React Nativeでアニメーション付きタブナビゲーションを作成する

アイコン、アニメーション、またはアバターを選択します。

<TabTrigger name="home" href="/" asChild>
  <TabButton labelAnimated={true} icon="Home">
    Home
  </TabButton>
</TabTrigger>

<TabTrigger name="profile" href="/profile" asChild>
  <TabButton
    labelAnimated={true}
    avatar={require('@/assets/img/thomino.jpg')}
  >
    Profile
  </TabButton>
</TabTrigger>

マルチステップフォームとオンボーディングフローの構築

これは非常によく使用します。オンボーディングやその他のユーザーフローに最適です。オンボーディングはユーザーをアクティブ化し、初期の離脱を減らすために不可欠です。

<MultiStep
  onComplete={handleComplete}
  onClose={handleClose}
  headerTitle="Get Started"
>
  <Step title="Profile">
    <Profile />
  </Step>
  <Step title="Role">
    <Role />
  </Step>
  <Step title="Capabilities">
    <Capabilities />
  </Step>
  <Step title="Review">
    <Review />
  </Step>
</MultiStep>

フィルターとフォーム用の再利用可能なチップコンポーネント

これは非常に基本的ですが、フィルターやフォームで頻繁に使用されます。

<Chip label="Custom" className="my-2 mx-1" size="xl" />

すべてのコンポーネントは私のドキュメントで確認できます。

NativeWindでテーマ変数を実装する

NativeWindはテーマ機能を非常に強力にします。varsを使用することで、1つのファイルでアプリ全体のテーマを切り替えることができます。これにより、ライトモードとダークモードが単なる後付けではなく、デザインシステムの中核部分であることを保証しています。

import { vars } from "nativewind";

export const themes = {
  light: vars({
    "--color-primary": "#000000",
    "--color-invert": "#ffffff",
    "--color-secondary": "#ffffff",
    "--color-background": "#F4F4F5",
    "--color-darker": "#F4F4F5",
    "--color-text": "#000000",
    "--color-highlight": "#7E55D8",
    "--color-border": "rgba(0, 0, 0, 0.15)",
  }),
  dark: vars({
    "--color-primary": "#ffffff",
    "--color-invert": "#000000",
    "--color-secondary": "#1e1e1e",
    "--color-background": "#141414",
    "--color-darker": "#000000",
    "--color-text": "#ffffff",
    "--color-highlight": "#7E55D8",
    "--color-border": "rgba(255, 255, 255, 0.15)",
  }),
};

Reanimatedでアニメーション付きダークモードトグルを構築する