📝

「RemixV2」で簡単な漢字読みクイズアプリを作成する

2024/04/10に公開

クイズアプリを作ります。

https://github.com/harukihosono/remix-quiz-app

要件・仕様

  • 4択クイズ
  • 漢字のクイズ
  • 5問
  • 正解率出す

1. 問題と答えを作る

app/data.tsのファイルを新規作成してデータを用意する。

app/data.ts
// ./app/data.ts
export const quizQuestions = {
    reading_questions: [
        {
            question: "「義理」の正しい読み方はどれか?",
            options: ["ぎり", "よし", "ぎれい", "りぎ"],
            answer: "ぎり"
        },
        {
            question: "「憂鬱」の読み方はどれか?",
            options: ["ゆうゆつ", "ゆううつ", "おもいみ", "うれい"],
            answer: "ゆううつ"
        },
        {
            question: "「躊躇」の読み方はどれか?",
            options: ["ちゅうちょ", "ちゅうど", "ためらい", "ちょうちょ"],
            answer: "ちゅうちょ"
        },
        {
            question: "「瑞々しい」の読み方はどれか?",
            options: ["みずみずしい", "すいすいしい", "りんりんしい", "ずいずいしい"],
            answer: "みずみずしい"
        },
        {
            question: "「喧嘩」の読み方はどれか?",
            options: ["けんか", "げんか", "こんか", "けんが"],
            answer: "けんか"
        }
    ]
};


2. スタイルを書く

app/styles.tsのファイルを新規作成してCSSを用意する。

app/styles.ts
/* src/App.css */
.quizPage {
    font-family: Arial, sans-serif;
    margin: 20px;
}

.questionSection {
    margin-bottom: 20px;
}

.questionCount {
    margin-bottom: 10px;
}

.questionText {
    margin-bottom: 20px;
}

.answerSection button {
    display: block;
    width: 100%;
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ddd;
    background-color: #f8f8f8;
    cursor: pointer;
}

3. スタイルを適用する

app/root.ts
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";

+import type { LinksFunction } from "@remix-run/node"; // or + cloudflare/deno

+import styles from "~/styles.css?url";

+export const links: LinksFunction = () => [
+  { rel: "stylesheet", href: styles },
+];

4. _indexページを更新する

app\routes\_index.tsxのファイルを更新する

app/data.ts
import React, { useState } from 'react';
import { json, LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { quizQuestions } from '~/data';

interface Question {
  question: string;
  options: string[];
  answer: string;
}

export const loader: LoaderFunction = async () => {
  return json(quizQuestions);
};

const QuizPage: React.FC = () => {
  const loadedData = useLoaderData<typeof quizQuestions>();
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  const [selectedAnswers, setSelectedAnswers] = useState<string[]>([]);
  const [showResult, setShowResult] = useState(false);
  const questions: Question[] = loadedData.reading_questions;

  const handleAnswerSelection = (selectedOption: string) => {
    const newAnswers = [...selectedAnswers, selectedOption];
    setSelectedAnswers(newAnswers);

    if (currentQuestionIndex + 1 < questions.length) {
      setCurrentQuestionIndex(currentQuestionIndex + 1);
    } else {
      setShowResult(true); // クイズ終了
    }
  };

  const resetQuiz = () => {
    setCurrentQuestionIndex(0);
    setSelectedAnswers([]);
    setShowResult(false);
  };

  const calculateScore = () => {
    let score = 0;
    questions.forEach((question, index) => {
      if (question.answer === selectedAnswers[index]) {
        score += 1;
      }
    });
    return score;
  };

  if (showResult) {
    const score = calculateScore();
    return (
      <div className="resultSection">
        <h2>クイズ結果</h2>
        <p>あなたのスコアは {score} / {questions.length} です。</p>
        <button onClick={resetQuiz}>もう一度チャレンジ</button>
      </div>
    );
  }

  return (
    <div className="quizPage">
      <div className="questionSection">
        <div className="questionCount">
          <span>Question {currentQuestionIndex + 1}</span>/{questions.length}
        </div>
        <div className="questionText">{questions[currentQuestionIndex].question}</div>
      </div>
      <div className="answerSection">
        {questions[currentQuestionIndex].options.map((option, index) => (
          <button key={index} onClick={() => handleAnswerSelection(option)}>
            {option}
          </button>
        ))}
      </div>
    </div>
  );
};

export default QuizPage;

完成😆

Discussion