フロントエンド開発で人気のライブラリである React は、Webアプリケーションの開発において広く使われています。
しかし、React は Webアプリケーションだけでなく、スマホ(モバイル)アプリケーションの開発にも使うことができます。
そのためには React Native というライブラリを使います。
このチュートリアルでは、React Nativeを使用してシンプルなタッチゲームを作成します。
React をある程度使ったことがある一方、 React Native は初めてという方を対象としていますので安心してください。
なお、今回作るコードは GitHub にあげてありますので、すぐ試したいかたは git clone しても OK です!
React Nativeとは
React Nativeは、Facebook(Meta)が提供するクロスプラットフォーム対応のアプリケーションフレームワークです。

React といえば Web ブラウザで動くアプリケーションを作るためのライブラリです。
一方、React Native は Web ブラウザ以外にも、異なるオペレーティングシステムであるiOSとAndroid上で、単一のコードベースからアプリケーションを開発できます。
また、JavaScriptという広く普及している言語を用いることで、多くの開発者が迅速にモバイルアプリケーション開発に取り組むことができるようになります。
このフレームワークのメリットの一つは、Web開発者がすでに習熟しているJavaScript (React) を活用して、ネイティブアプリの開発が可能になる点です。
これにより、新たにObjective-CやKotlinなどのネイティブアプリ開発言語を学ぶ必要がなく、既存のスキルセットをそのまま利用できます。
そのため、フロントエンジニアがモバイルアプリ開発に参入する際に、React Nativeは最も適した選択肢となります。
実際、React NativeはFacebookやInstagram、UberEatsといった世界的に有名なアプリにも採用されていることから、これからの成長も期待されています。
前提条件
本チュートリアルを始めるにあたって、React Native を効率的に開発できるフレームワークである Expo を使います。
Expoは、React Nativeでのアプリケーション開発を効率化するためのオープンソースプラットフォームであり、設定作業を大幅に簡略化します。
ちなみに本チュートリアルでは iOSアプリケーションの開発を行いますが、XcodeやXcode Command Line Toolsが必要になります。
これらはAppleの開発ツールであり、iOSアプリをシミュレートするための環境を提供します。
もしまだ準備が整っていなければ、Expoのドキュメントにあるインストールガイドに従ってセットアップを行ってください。
また、このチュートリアルを進める上でのその他の要件は以下の通りです。
- Node.jsがシステムにインストールされており、コマンドラインからアクセス可能であること
- npm(Node.jsのパッケージマネージャー)が利用できる状態であること
- ターミナルやコマンドプロンプトの基本的な使用法に精通していること
- JavaScriptやReactの基本的な概念についての知識を有していること
それではスマホアプリを作ってみましょう!
プロジェクトの準備
まずは、開発用の新しいReact Nativeプロジェクトを作成していきます。
npx コマンドを用いて作れるので、ターミナルを開きましょう。
npx create-expo-app touch-quiz-gameこのコマンドにより、touch-quiz-gameという名前の新しい React Native プロジェクトを生成します。
こうすることで、必要なファイルやディレクトリ構造が自動的にセットアップされます。
次に、作成されたばかりのプロジェクトフォルダに移動するために、次のコマンドを入力します。
cd touch-quiz-gameそして、iOSシミュレーターでアプリケーションを起動するためには、以下のようにコマンドを実行します。
cd touch-quiz-gameこれにより、開発しているアプリケーションがiOSシミュレーターで開かれます。
正常にコマンドが実行されると、新しいウィンドウが開いてiOSシミュレーターが起動し、Expoが提供するデフォルトの起動画面が表示されます。
この段階で、シミュレーター上でアプリが実行されるのを確認できれば、プロジェクトのセットアップは成功です。

もし画面に何も表示されない、あるいはエラーが生じた場合は、コマンドの入力ミスや前提条件が正しく準備されていない可能性があります。
ターミナルにエラーが出ていないかなどを確認してみましょう。
ゲーム作成に必要なファイル準備
デフォルトで作成されているメインコンポーネントは App.js というファイルに書かれています。
しかし、一つのコンポーネントを大きくしていくと、コードが読みにくくなってしまいます。
そのため、今回は以下のようにファイルを分割していきます。
- App.js(メインコンポーネント)
- styles.js(スタイルシート)
- utils.js(ユーティリティ関数)
- components/OptionButton.js(オプションボタンコンポーネント)
最終的には以下のようなファイル構成になります。
.
├── App.js # メインコンポーネント
├── README.md
├── app.json
├── assets
├── babel.config.js
├── components
|   └── OptionButton.js # オプションボタンコンポーネント
├── node_modules
├── package-lock.json
├── package.json
├── styles.js # スタイルシート
└── utils.js # ユーティリティ関数styles.js(スタイリング用のファイル)
まずはじめに、プロジェクトの最上位(ルート)に styles.js という新しいファイルを作成しましょう。
これはReact Nativeアプリのスタイリングに関する情報を一箇所にまとめるためのファイルです。
下記のコードを styles.js ファイルに入力してください。
// styles.js
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
  // アプリ全体の背景色や配置などを定義
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#fff',
  },
  // 指示文全体のスタイルを定義
  instructions: {
    fontSize: 20,
    marginBottom: 20,
    textAlign: 'center',
    color: '#333',
  },
  // 指示文のうち、強調したいテキストのスタイルを定義
  emphasize: {
    fontWeight: 'bold',
    fontSize: 32,
  },
  // ボタンのグリッドレイアウトを定義
  grid: {
    width: '90%',
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between',
  },
  // ボタンの大きさ、透明度、角の丸みなどを設定しています。
  button: {
    width: '30%',
    height: '30%',
    aspectRatio: 1,
    justifyContent: 'center',
    alignItems: 'center',
    marginBottom: 10,
    opacity: 0.85,
    borderRadius: 15,
  },
  // ボタンの文字色、フォントサイズ、文字の太さを定義
  buttonText: {
    color: '#fff',
    fontSize: 42,
    fontWeight: 'bold',
  },
  // スコアを表示するテキストのスタイルが定義
  score: {
    marginTop: 20,
    fontSize: 24,
  },
});ここでは、アプリ内の異なる要素に適用するスタイルを定義しています。
StyleSheet というReact Nativeの機能を使って、それぞれのスタイルを作成し、それをこのファイルからエクスポートすることによって、アプリの他の部分から利用可能にしています。
utils.js(ユーティリティ関数のファイル)
プロジェクトのルートディレクトリに utils.js ファイルを新たに作成してください。
このファイルは、ゲームの動作に必要な補助関数を定義し、他のファイルでの再利用を可能にするためのものです。
以下のコードを utils.js に追加します。
ランダムな色や数字を生成する関数、ゲームオプションを生成する関数などが含まれています。
// utils.js
// ランダムな色を文字列で返す関数
export const getRandomColor = () => {
  const colors = Object.keys(colorNames);
  return colors[Math.floor(Math.random() * colors.length)];
};
// 1から9までのランダムな数字を返す関数
export const getRandomNumber = () => Math.ceil(Math.random() * 9);
// 色の名前とそのRGB値をマッピングするオブジェクト
export const colorNames = {
  'rgba(255, 0, 0, 0.8)': 'Red',
  'rgba(0, 0, 255, 0.8)': 'Blue',
  'rgba(0, 128, 0, 0.8)': 'Green',
};
// 正解を含むゲームオプションの配列を生成する関数
export const generateOptions = (correctAnswer) => {
  // 9つのオプションを持つ配列を生成する
  let options = new Array(9).fill(null).map(() => ({
    color: getRandomColor(),
    number: getRandomNumber(),
  }));
  // 正解を配列のランダムな位置に挿入する
  const correctIndex = Math.floor(Math.random() * options.length);
  options[correctIndex] = correctAnswer;
  return options;
};utils.js にこれらの関数を定義することで、ゲームに必要なランダムな要素を簡単に生成することができます。
各関数は export されているので、他のファイルからインポートして利用することができます。
これによって、ゲームのロジックを構築する際にコードの再利用性が高まり、より管理しやすいコードベースを実現できます。
OptionButton.js(オプションボタンのコンポーネント)
次は、components という新しいフォルダをプロジェクト内に作成し、その中に OptionButton.js というファイルを作成してください。
このファイルでは、ユーザーが選択できるオプションボタン(タッチするボタン)を表示するコンポーネントを定義します。
OptionButton.js に以下のコードを追加します。
このコードは、タッチ操作が可能なボタンとして機能し、ボタンを押したときの動作を引数から受け取ることができます。
// components/OptionButton.js
import { Text, TouchableOpacity } from 'react-native';
import styles from '../styles';
// オプションボタンのコンポーネントを定義
const OptionButton = ({ option, onPress }) => (
  <TouchableOpacity
    style={[styles.button, { backgroundColor: option.color }]}
    onPress={onPress}
  >
    <Text style={styles.buttonText}>{option.number}</Text>
  </TouchableOpacity>
);
// このコンポーネントを他のファイルから利用できるようにエクスポート
export default OptionButton;このコンポーネントを使用すると、色と数字が設定されたオプションボタンを画面上に表示することができます。
option プロパティには色と数字の情報を持ったオブジェクトが渡され、onPress プロパティにはボタンが押されたときの処理を定義する関数が渡されます。
App.js(メインコンポーネント)
App.js はプロジェクト作成時に既に存在し、アプリケーションのメインコンポーネントを含んでいます。
このファイルで、アプリケーション全体のレイアウトや状態管理を行い、作成した他のコンポーネントを組み合わせていきます。
App.js の中身を以下のように丸っと書き換えましょう。
このコードはアプリケーションのロジックを構築し、インターフェースを設定します。
少々長いのですが、ところどころにコメントを追加していますので、コメントを読みながらそれぞれのコードを理解していきましょう。
// App.js
import React, { useState } from 'react';
import { Text, View, Alert } from 'react-native';
import styles from './styles';
import { getRandomColor, getRandomNumber, colorNames, generateOptions } from './utils';
import OptionButton from './components/OptionButton';
export default function App() {
  // 正解となる色と数字の状態をuseStateで管理
  const [correctAnswer, setCorrectAnswer] = useState({
    color: getRandomColor(),
    number: getRandomNumber(),
  });
  // オプションの状態をuseStateで管理
  const [options, setOptions] = useState(generateOptions(correctAnswer));
  // スコアの状態をuseStateで管理
  const [score, setScore] = useState(0);
  // ボタン押下時の処理を定義
  const handlePress = (color, number) => {
    if (color === correctAnswer.color && number === correctAnswer.number) {
      setScore(prevScore => prevScore + 1);
      const newCorrectAnswer = {
        color: getRandomColor(),
        number: getRandomNumber(),
      };
      setCorrectAnswer(newCorrectAnswer);
      setOptions(generateOptions(newCorrectAnswer));
    } else {
      Alert.alert(<code>Wrong! Your score is ${score}.\nTap OK to play again.</code>, null, [
        { text: 'OK', onPress: resetGame }
      ]);
    }
  };
  // ゲームをリセットする関数
  const resetGame = () => {
    setScore(0);
    const newCorrectAnswer = {
      color: getRandomColor(),
      number: getRandomNumber(),
    };
    setCorrectAnswer(newCorrectAnswer);
    setOptions(generateOptions(newCorrectAnswer));
  };
  // コンポーネントのUIを定義
  return (
    <View style={styles.container}>
      <Text style={styles.instructions}>
        Tap the <Text style={styles.emphasize}>{colorNames[correctAnswer.color]}</Text> button with the number <Text style={styles.emphasize}>{correctAnswer.number}</Text>
      </Text>
      <View style={styles.grid}>
        {options.map((option, index) => (
          <OptionButton
            key={index}
            option={option}
            onPress={() => handlePress(option.color, option.number)}
          />
        ))}
      </View>
      <Text style={styles.score}>Score: <Text style={styles.emphasize}>{score}</Text></Text>
    </View>
  );
}App.js はゲームのロジックを担っており、ゲームの状態管理(スコアなど)やユーザーインタラクション(ユーザー操作への反応)を取り扱います。
例えば、正解を選ぶとスコアが増加し、誤った選択をするとゲームがリセットされます。
これでコードの準備が整いましたので、完成です!
次は、こちらのコードをもとに、アプリケーションの動作を確認していきましょう。
動作確認
アプリの起動
ソースコードの変更はホットリロードですぐに反映されますので、コードを書き換えた時点からシミュレータで確認できます。
もし一度停止していた場合は、以下のコマンドで再度起動できます。
npm run iosでは、実際にアプリを触ってみましょう。
初期表示の確認
初期表示では以下の画面のように、指示文やボタン、そして 0 点のスコアが表示されているかと思います。
以下の例では、色が Blue(青)であり、数字が 7 であるボタンが正解ですので、押すとスコアが +1 になるような状態です。

ちなみに、ボタン配置はランダムなので上記のように正解のボタンが 2つ以上存在する場合もあります。
余力がある方は、正解のボタンは1つだけになるように機能変更してもいいかもしれませんね。
ゲームの動作確認(正解時)
実際にやってみましょう。
指示文にマッチした色・数字のボタンをタッチすると、スコアが +1 されて、新しい指示文が表示されます。
何度か続けると、スコアが増えていきます。

ゲームの動作確認(不正解時)
一方、間違ったボタンをタッチしてしまうとアラートが表示され、最終スコアが表示されます。

また、「OK」を押すとスコアがリセットされ、新しいゲームが開始されます。

以上が基本的なゲームの流れになります。
アプリを改造するアイデア
このチュートリアルでは、シンプルなタッチゲームを作成しました。
今回は初めて React Native を触る方も対象としているため、あえてシンプルなゲームにしています。
しかし、たとえば以下のようなアイデアでアプリを改造してみると、より面白いゲームになるかもしれません。
- タイムアタックモードを追加する
- 「色」「数字」以外にも「形」「文字」などを追加する
- 指示文の「Red」などをあえて違う色(Red なら青文字)で表示する
- ボタンを押すと音が鳴るようにする
- ランキング機能を追加する
ぜひ、自分なりのアイデアでアプリを改造してみてください!
React Native をちゃんと学びたい方へ
いまは Web 開発に特化している方の中にも、将来的な選択肢を増やすために React Native を学んでみたくなった方がいるかと思います。
しかし、React とは異なる記法も多いと感じたのではないでしょうか?
React Native 独自の記法があるのはもちろん、モバイルアプリならではの開発・デバッグ手法など、ギャップが多いため、一度体系的に学んでおくのがおすすめです。
おすすめは、執筆時点で受講生が 1,000 人を超えるこちらの Udemy 講座です!
>>> React Native, Firebase, Expo でアプリ開発をゼロから始めよう! 
総受講時間はなんと 40時間オーバーとなっており、1講座でプログラミングスクール並みの学習ボリュームがあります。
独学で React Native を学びたい方は、こちらの講座で学習しておけば間違いありません。
コスパよく React を学習できる Udemy 講座人気ランキング
ちなみに姉妹サイトの Learning Next では、React を独学で学べる Udemy 講座の人気ランキングや、各講座の受講生レビューをもとにした分析スコアを公開しています。
「学習にあまりお金をかけたくない…」「スクールに通う時間がない」という方は、こちらを参考に Udemy 講座の学習も検討してはいかがでしょうか?
▶️ UdemyでReactを学べる講座の人気ランキング – Learning Next
ひとめで良い点・悪い点、さらにおすすめポイントが分かりますので、講座選びで失敗したくない方はぜひ活用してみてください!

