📱

React Native ExpoとTailwind.cssで始めるモバイルアプリ案内

2023/12/01に公開
2

React(Next.js)およびTailwind.css経験者向けのアプリ開発入門

はじめに

モバイルアプリを作成したいと思って学習を始めても
独自の言語とスタイリングの説明が長くて途中で飽きてしまうことはありませんか?
そんなあなたへTailwindを利用したモバイルアプリの開発をご案内いたします。
Xcodeの必要がなく、コピペで5分くらいで実機表示出来ますので、まずはサクッとイメージだけでも掴んで頂けましたと思います。

動作確認環境

  • MacBook Pro M1 Sonoma
  • Node v20.0.0
  • tailwindcss@3.3.2
  • expo 49.0.15
  • nativewind 2.0.11
  • iPhone iOS 17.1.1
    ※内容は記述時点のものとなります。

モチベーション

React Nativeの大きな特徴は次の2つです。 (React,TypeScriptの習得者にとって)

(1)言語を覚える必要がない

TypesScriptで記述出来ます。
React Native独自の設定を少し覚える必要はありますが、
あとは使い慣れたReactです。(AxiosやReduxなどがそのまま使えます。)

(2)スタイリングにcssが使える

デフォルトではReact Native独自の書き方となりますが
今回は使い慣れたclassNameTailwind.cssを使う手法で作ります。(混在も可能)
(ネット上に豊富にあるTailwindのコードをコピーして使えます。)

ほとんどのアプリの学習は独自言語とスタイリングの説明からですので
この2つを飛ばせるのは大きいですよ!!

動作確認アプリ「Expo Go」のインストール

画面のQRコードを読み込んで実機で確認するためのアプリをインストールします。

App Store
https://apps.apple.com/jp/app/expo-client/id982107779

Google Play
https://play.google.com/store/apps/details?id=host.exp.exponent&pli=1

ファイル構成

追加、変更するファイルです。簡潔な説明のために今回は全てルートです😱

MyApp/
├── App.tsx
├── babel.config.js
├── my-app.d.ts ←追加
├── tailwind.config.js
└── tsconfig.json

Expo cliのインストール

グローバルにExpo cliをインストールします。

npm install -g expo-cli

ステップ1: Expoプロジェクトのセットアップ(TypeScript)

Expo CLIを使用してTypeScriptテンプレートで新しいプロジェクトを作成します。

expo init MyApp --template expo-template-blank-typescript
cd MyApp

このコマンドにより、TypeScriptをサポートする新しいExpoプロジェクトが作成されます

ステップ2: Tailwind CSSとNativeWindのインストール

プロジェクトディレクトリで、Tailwind CSSとNativeWindをインストールします。

npm install --dev tailwindcss@3.3.2
npm install nativewind
npm install --save-dev @types/react-native

ステップ3: Tailwind CSSの設定

Tailwind CSSの設定ファイルを生成します。

npx tailwindcss init

ステップ4: Tailwind Configのカスタマイズ

tailwind.config.jsを開き、TypeScriptファイルを含むようにcontentプロパティを更新します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./App.{js,jsx,ts,tsx}",
    "./app/**/*.{js,jsx,ts,tsx}",
    // 他のカスタムディレクトリがあればここに追加
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

ステップ5: babel.config.jsの設定

babel.config.jsを開き、NativeWindプラグインを追加します。

babel.config.js
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['nativewind/babel'],
  };
};

ステップ6: my-app.d.tsの追加と設定

my-app.d.tsを追加します。

my-app.d.ts
/// <reference types="nativewind/types" />

ステップ7: App.tsx

App.tsxにコードを書いていきます。
最初からあるコードを全て消して次のコードに書き換えます。

App.tsx
import React, { useState } from "react";
import { Text, TouchableOpacity, View } from "react-native";

export default function App() {
  const [text, setText] = useState<string>("Hello, React Native");
  const [count, setCount] = useState<number>(0);

  const handleIncrement = () => setCount((prevCount) => prevCount + 1);
  const handleDecrement = () =>
    setCount((prevCount) => (prevCount > 0 ? prevCount - 1 : 0));
  const toggleText = () =>
    setText((currentText) =>
      currentText === "Hello, React Native"
        ? "テキストが変更されました!"
        : "Hello, React Native"
    );

  return (
    <View className="flex-1 items-center justify-center bg-gray-100">
      <Text className="text-blue-500 text-xl">{text}</Text>
      <TouchableOpacity
        onPress={toggleText}
        className="mt-6 h-fit w-fit rounded-full bg-blue-500 px-4 py-2"
      >
        <Text className="color-white text-xl font-bold drop-shadow-2lx">
          テキストを変更
        </Text>
      </TouchableOpacity>

      <Text className="text-2xl mt-10 text-gray-500 font-bold">{count}</Text>
      <View className="mt-[20px] flex-row justify-center items-center">
        <TouchableOpacity
          onPress={handleDecrement}
          className="border-1 h-[50px] w-[50px] items-center justify-center rounded-full bg-blue-500 shadow"
        >
          <Text className="color-white text-xl font-bold"></Text>
        </TouchableOpacity>

        <TouchableOpacity
          onPress={handleIncrement}
          className="border-1 ml-20 h-[50px] w-[50px] items-center justify-center rounded-full bg-blue-500 shadow"
        >
          <Text className="color-white text-xl font-bold"></Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

View,Text,TouchableOpacityなどのタグもありますが、見慣れたコードだと思います。

まずは
View -> divタグ
Text -> pタグ
TouchableOpacity ->クリック出来る
くらいのイメージでよいと思います。

ステップ8: Expoでのアプリ実行

npm start

次の様な画面が表示されます。
iPhone場合はカメラでQRコードを読み込んでリンクをクリックするとExpo Goが起動します。

Starting Metro Bundler
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
█ ▄▄▄▄▄ █▄▀▀▄▄▄██ █ ▄▄▄▄▄ █
█ █   █ ███▄█  ▀▄▄█ █   █ █
█ █▄▄▄█ ██▄▀▄▀▄██▀█ █▄▄▄█ █
█▄▄▄▄▄▄▄█ █ ▀▄▀▄▀ █▄▄▄▄▄▄▄█
█▄ █ ▄▀▄▀█ ▄▄▀▀█▀ █▄█▀█▀▀▄█
█ ▄▄▀▀█▄ ▀▀  ▀▄▄▄▀▀███▄▀▀ █
█▀█▄▄▄▀▄█ ▄█▄▄▀▄ █ ▄▀▀█▀ ██
█ ▄▀ ▀ ▄ ▄▀█ ▄▄█ ▄▀ ██▄▀  █
█▄██▄█▄▄█▀ ▀▀   █ ▄▄▄  ▄▀▄█
█ ▄▄▄▄▄ ██▀ ▄  ▄█ █▄█ ██▀ █
█ █   █ █ █▀▀▀██▄ ▄  ▄ █▀▀█
█ █▄▄▄█ █▀▀▄  █▄ ▄█▀▀▄█   █
█▄▄▄▄▄▄▄█▄█▄▄██▄▄▄▄█▄▄███▄█

› Metro waiting on exp://192.168.0.169:19000
› Scan the QR code above with Expo Go (Android) or the Camera app (iOS)

› Press a │ open Android
› Press i │ open iOS simulator
› Press w │ open web

› Press r │ reload app
› Press m │ toggle menu

› Press ? │ show all commands

無事に表示されましたでしょうか?

今回はここまでとなります。
おつかれさまでした。🐤

そのあとは

Expo Routerでのページ追加、リンク、ルーティング(Next.jsに似ている)
React Navigationでのページ送りアニメなどモバイルに特化した事を少し覚えれば
Reactの手法でアプリを組んでいけます。
また、ExpoはカメラやGPSなどスマホの機能を簡単に利用出来るライブラリもたくさん準備されています。
アプリを公開するまでにはアイコン作成やビルド(実行ファイル書き出し)、AppStoreへの登録などの作業が発生するのですが、ReactやNext.jsを修得された方なら自分で調べながら容易にクリアされるかと思います。

おわりに

アドベントカレンダー2023のトップバッターに指名されたので(されてない)折角ですので
モバイルアプリ開発の敷居を下げられるような内容にしたいと思いました。
React Nativeは今や日々進化する生成AIのAPIをモバイルですぐに試せる素晴らしいフレームワークですので是非お試しください。
記事を読んだ一人でも多くの方がReact Nativeに興味をお持ち頂きモバイルアプリ開発の世界への第一歩を踏み出す一助になれば幸いです。

それでは
🎄メリークリスマス&
🎍良いお年をお迎えください🎉

参考URL

Tailwind.cssを利用するためのライブラリ
https://www.nativewind.dev/
Expo公式
https://expo.dev/

Taka Xはこちら

Discussion

kusirakusirakusirakusira

記事ありがとうございます。
今はappディレクトリなので、tailwind.config.jsのcontentのパスが少し異なることに注意が必要ですね。

tailwind.config.js 5行目
- "./src/**/*.{js,jsx,ts,tsx}",
+ "./app/**/*.{js,jsx,ts,tsx}",

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./App.{js,jsx,ts,tsx}",
    "./app/**/*.{js,jsx,ts,tsx}",
    // 他のカスタムディレクトリがあればここに追加
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};