Introduction to React Components

Core React Concepts That Power Your Quiz App

This module helps you understand the key React concepts that make your Quiz App work. You'll learn how components break down the UI, how state and props control the data flow, how we fetch real-time questions using an API, and how events are handled to keep the app interactive. By the end of this module, you’ll clearly understand how each part of the app connects behind the scenes.

React Components

React components allow us to split the UI into reusable and manageable parts. Each screen or section in the Quiz App is a separate component. This makes the app easy to read, maintain, and expand.

In your app, the main components include:

  • App.jsx: This is the root component. It controls the screen flow (welcome screen, quiz screen, score screen) and maintains the main state.
  • WelcomeScreen.jsx: Displays the animated welcome screen and lets the user pick a quiz category.
  • Quiz.jsx: Responsible for fetching quiz questions, handling answers, and displaying each question one at a time.
  • QuestionCard.jsx: A small presentational component that shows the current question and answer choices.
  • ScoreCard.jsx: Displays the final score and a list of correct/incorrect answers.

Each component is a JavaScript function that returns JSX, which is how we describe the UI using HTML-like syntax.

State Management with useState and useEffect

React’s state system helps us remember things like which category was chosen, which question we’re on, and how many points the user has scored.

We use useState() to store values that can change during the app's lifecycle. For example, in App.jsx, we store which step the app is in (welcome, quiz, or score):

const [step, setStep] = useState("welcome");

In Quiz.jsx, we manage state for:

  • The list of fetched questions
  • The current question index
  • The user's score
  • Whether data is loading

Example:

const [questions, setQuestions] = useState([]);
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
const [score, setScore] = useState(0);

We also use useEffect() to run code when the component loads. This is where we fetch questions from the trivia API:

useEffect(() => {
  fetchQuestions(category);
}, [category]);

This hook runs only once when the component mounts or when the category changes.

Event Handling

To respond to user actions like button clicks, we use event handlers.

For example, when the user selects an answer:

const handleAnswerSelect = (selectedOption) => {
  if (selectedOption === correctAnswer) {
    setScore(score + 1);
    setFeedback("Correct");
  } else {
    setFeedback("Incorrect");
  }

  setTimeout(() => {
    setCurrentQuestionIndex(currentQuestionIndex + 1);
  }, 1000);
};

This function checks if the selected option is correct, updates the score, shows feedback, and then moves to the next question after a short delay.

When the user selects a category and starts the quiz from the welcome screen:

const confirmCategory = () => {
  if (category) {
    setStep("quiz");
  }
};

These event handlers make the app dynamic and interactive.

Props

Props are how we pass data from one component to another.

In your app, Quiz.jsx sends data into QuestionCard.jsx:

<QuestionCard
  question={currentQuestion.question}
  options={currentQuestion.options}
  onAnswerSelect={handleAnswerSelect}
/>

And then inside QuestionCard.jsx, we receive these values:

function QuestionCard({ question, options, onAnswerSelect }) {
  // JSX that uses the question and options
}

This setup allows components to stay reusable and focused only on what they need to do.

Fetching Questions from an API

Your app uses real data from the Open Trivia Database API. When the user selects a category, the app sends a request to fetch 10 questions of that category.

Example:

const fetchQuestions = async (categoryId) => {
  const response = await fetch(`https://opentdb.com/api.php?amount=10&category=${categoryId}&difficulty=easy&type=multiple`);
  const data = await response.json();
  const formattedQuestions = data.results.map((q) => ({
    question: q.question,
    correctAnswer: q.correct_answer,
    options: shuffle([...q.incorrect_answers, q.correct_answer]),
  }));
  setQuestions(formattedQuestions);
};

The shuffle() function is used to randomize the order of the answer options for each question. This makes the quiz fair and unpredictable.