React Nativeで、拡張性のあるクイズアプリ簡易版を作成する②

前回の『拡張性のあるクイズアプリ簡易版』では、正答(correctAnswer)と、問題文(problemText)を渡せば、別々の問題を表示できることになります。

そこで、これらを、オブジェクトリテラルの配列で定義し、『次の問題』ボタンを押すと、問題が更新されるように拡張します。今後データベースからデータを引っ張ってくる拡張を想定し、作成するオブジェクトリテラル内に、correctAnswer,problemTextプロパティに加え、idプロパティを追加します。

 

プログラムの前半だけを下記のように変えればよいです。

import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Button } from "react-native";
import { useState } from "react";

const problemArrayData = [
  {
    id: 1,
    correctAnswer: "b",
    problemText:
      "日本で一番大きな湖は?\r\na. 宍道湖 b. 琵琶湖 c. 十和田湖 d. 浜名湖",
  },
  {
    id: 2,
    correctAnswer: "c",
    problemText:
      "日本の最南端の島は?\r\na. 与那国島  b. 南鳥島 c. 沖ノ鳥島 d. 西表島",
  },
  {
    id: 3,
    correctAnswer: "a",
    problemText:
      "日本の都道府県で2番目に大きい都道府県は?\r\na.岩手県  b.福島県  c.長野県 d. 新潟県",
  },
];

export default function App() {
  const correctAnswer = problemArrayData[1].correctAnswer;
  const problemText = problemArrayData[1].problemText;
      ・
      ・
      ・
一番上に、『次の問題』ボタンを作成します。
export default function App() {
  const [correctAnswer, setCorrectAnswer] = useState("");
  const [problemText, setProblemText] = useState("");

  const pressNextHandler = () => {
    const randomNumber = Math.floor(Math.random() * 3);
    setCorrectAnswer(problemArrayData[randomNumber].correctAnswer);
    setProblemText(problemArrayData[randomNumber].problemText);
  };
       ・
       ・
       ・(省略)
       ・
 

  return (
    <View style={styles.container}>
      <Button title="次の問題" onPress={pressNextHandler} />
      <Text>{problemText}</Text>
      <View style={styles.buttonContainer}>
        <Button title={buttonText_a} onPress={pressHandler_a} />
        <Button title={buttonText_b} onPress={pressHandler_b} />
        <Button title={buttonText_c} onPress={pressHandler_c} />
        <Button title={buttonText_d} onPress={pressHandler_d} />
      </View>
      <Text>{correctText}</Text>
      <Text>{explanationText}</Text>
      <StatusBar style="auto" />
    </View>
  );
}
 
さて、次に、『終了』ボタンを押すと、それまでに、問題に答えた回数(totalAnswerNumber)と、正答数(correctAnswerNumber)を表示できるようにします。
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Button } from "react-native";
import { useState } from "react";

const problemArrayData = [
  {
    id: 1,
    correctAnswer: "b",
    problemText:
      "日本で一番大きな湖は?\r\na. 宍道湖 b. 琵琶湖 c. 十和田湖 d. 浜名湖",
  },
  {
    id: 2,
    correctAnswer: "c",
    problemText:
      "日本の最南端の島は?\r\na. 与那国島  b. 南鳥島 c. 沖ノ鳥島 d. 西表島",
  },
  {
    id: 3,
    correctAnswer: "a",
    problemText:
      "日本の都道府県で2番目に大きい都道府県は?\r\na.岩手県  b.福島県  c.長野県 d. 新潟県",
  },
];

export default function App() {
  const [correctAnswer, setCorrectAnswer] = useState("");
  const [problemText, setProblemText] = useState("");
  const [totalAnswerNumber, setTotalAnswerNumber] = useState(0);
  const [correctAnswerNumber, setCorrectAnswerNumber] = useState(0);
  const [finishedText, setFinishedText] = useState("");

  const pressNextHandler = () => {
    const randomNumber = Math.floor(Math.random() * 3);
    setCorrectAnswer(problemArrayData[randomNumber].correctAnswer);
    setProblemText(problemArrayData[randomNumber].problemText);
    setTotalAnswerNumber((prevState) => prevState + 1);
  };

  const pressFinishHandler = () => {
    setFinishedText(
      `Finished!\r\n解いた問題数は${totalAnswerNumber}\r\n正答数は${correctAnswerNumber}です。`
    );
  };

  const [buttonText_a, setButtonText_a] = useState("a");
  const [buttonText_b, setButtonText_b] = useState("b");
  const [buttonText_c, setButtonText_c] = useState("c");
  const [buttonText_d, setButtonText_d] = useState("d");
  const [correctText, setCorrectText] = useState("");
  const [explanationText, setExplanationText] = useState("");

  const pressHandler_a = () => {
    if (buttonText_a == correctAnswer) {
      setCorrectText("Correct");
      setExplanationText("");
      setCorrectAnswerNumber((prevState) => prevState + 1);
    } else {
      setCorrectText("Incorrect!");
      setExplanationText(`正解は${correctAnswer}でした。`);
    }
  };

  const pressHandler_b = () => {
    if (buttonText_b == correctAnswer) {
      setCorrectText("Correct");
      setExplanationText("");
      setCorrectAnswerNumber((prevState) => prevState + 1);
    } else {
      setCorrectText("Incorrect!");
      setExplanationText(`正解は${correctAnswer}でした。`);
    }
  };

  const pressHandler_c = () => {
    if (buttonText_c == correctAnswer) {
      setCorrectText("Correct");
      setExplanationText("");
      setCorrectAnswerNumber((prevState) => prevState + 1);
    } else {
      setCorrectText("Incorrect!");
      setExplanationText(`正解は${correctAnswer}でした。`);
    }
  };

  const pressHandler_d = () => {
    if (buttonText_d == correctAnswer) {
      setCorrectText("Correct");
      setExplanationText("");
      setCorrectAnswerNumber((prevState) => prevState + 1);
    } else {
      setCorrectText("Incorrect!");
      setExplanationText(`正解は${correctAnswer}でした。`);
    }
  };

  return (
    <View style={styles.container}>
      <View style={styles.nextFinishButtonContainer}>
        <Button title="次の問題" onPress={pressNextHandler} />
        <Button title="終了" onPress={pressFinishHandler} />
      </View>
      <Text>{problemText}</Text>
      <View style={styles.selectButtonContainer}>
        <Button title={buttonText_a} onPress={pressHandler_a} />
        <Button title={buttonText_b} onPress={pressHandler_b} />
        <Button title={buttonText_c} onPress={pressHandler_c} />
        <Button title={buttonText_d} onPress={pressHandler_d} />
      </View>
      <Text>{correctText}</Text>
      <Text>{explanationText}</Text>
      <Text style={styles.finishedText}>{finishedText}</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  nextFinishButtonContainer: {
    flexDirection: "row",
    justifyContent: "space-around",
    width: "80%",
  },
  selectButtonContainer: {
    flexDirection: "row",
    justifyContent: "space-around",
    width: "80%",
  },
  finishedText: {
    marginTop: 30,
    fontSize: 20,
  },
});
 
データを別のJavaScript に記述し、App.jsへはimport してきます。
データを入れる際に、CodeWhisperがひな形を自動で作成してくれるのでかなり楽です。
ProblemEntity.js
export const problemArrayData = [
  {
    id: 1,
    correctAnswer: "b",
    problemText:
      "日本で一番大きな湖は?\r\na. 宍道湖 b. 琵琶湖 c. 十和田湖 d. 浜名湖",
  },
  {
    id: 2,
    correctAnswer: "c",
    problemText:
      "日本の最南端の島は?\r\na. 与那国島  b. 南鳥島 c. 沖ノ鳥島 d. 西表島",
  },
 
App.jsの冒頭
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Button } from "react-native";
import { useState } from "react";
import { problemArrayData } from "./ProblemEntity";