Project Demo Address

Project Demo Address

Program source code

Program source code

Video tutorial

Video tutorial

Vue version and applets version

Vue version

Applets version

Project code structure

preface

The Elegance of the React framework is self-evident. The component-based programming philosophy makes the code developed by the React framework simple and easy to understand, but the early writing of React class components is a bit cumbersome. React Hooks are one of the most interesting features since React 16.8 was released. They simplify the writing of existing code and will become the mainstay of future React applications.

In this article, I will give you a quick introduction to React Hooks from scratch. Address for online demonstration of this project:

In this project, the following knowledge points will be used:

  • React componentized design idea
  • The React State and Props
  • Use of React functional components
  • Use of React Hooks useState
  • React Hooks useEffect
  • React uses Axios to ask the remote interface for questions and answers
  • React uses Bootstrap to beautify the interface

Hello React

(1) Install node.js official website link

(2) Install vscode official website link

(3) Install the creat-React-app functional component, which can be used to initialize a project, that is, generate a new project according to a certain directory structure. Open a CMD window and enter:

npm install --g create-react-app 
npm install --g yarn
Copy the code

(-g indicates global installation.)

If installation fails or is slow. To change the source, you can use Taobao NPM image. The setting method is as follows:

npm config set registry https://registry.npm.taobao.org
Copy the code

Run the command again

npm install --g create-react-app
npm install --g yarn
Copy the code

(4) In the directory where you want to create the project such as D:/project/ open CMD command type

create-react-app react-exam
Copy the code

Create a project named react-exam using the creat-react-app command

When the installation is complete, move to the newly created directory and start the project

cd react-exam
yarn start
Copy the code

Once you run this command, the new Localhost :3000 React application will pop up a new window.

Project directory structure

Right-click the react-exam directory and open it with vscode. The react-exam project has a /public and/SRC directory, as well as node_modules,.gitignore, readme. md, and package.json.

In directory /public, the important file is index.html, and one line of code is the most important

<div id="root"></div>
Copy the code

This div acts as a mount point for our entire application

The/SRC directory will contain all of our React code.

To see how the environment automatically compiles and updates your React code, find the file/SRC/app.js: where

        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
Copy the code

Modified to

        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"> Learn React </a>Copy the code

After you save the file, you’ll notice that localhost:3000 compiles and refreshes the new data.

React-exam project

1. Make the home page

1. Install project dependencies and add to package.json:

  "dependencies": {
    "@testing-library/jest-dom": "^ 4.2.4"."@testing-library/react": "^ 9.3.2." "."@testing-library/user-event": "^ 7.1.2." "."react": "^ 16.13.1"."react-dom": "^ 16.13.1"."react-scripts": "3.4.1 track."."axios": "^ 0.19.2"."bootstrap": "^ 4.5.0." "."he": "^ 1.2.0"."react-loading": "^ 2.0.3"."reactstrap": "^ 8.4.1"
  },
Copy the code

Execute command:

yarn install
Copy the code

Modify index.js to import the bootstrap style

import "bootstrap/dist/css/bootstrap.min.css";
Copy the code

Modify the app.css code

html {
  width: 80%;
  margin-left: 10%;
  margin-top: 2%;
}

.ansButton {
  margin-right: 4%;
  margin-top: 4%;
}
Copy the code

Modify app.js to introduce Quiz component

import React from 'react';
import './App.css'
import { Quiz } from './Exam/Quiz';

function App() {
  return (
    <div className = 'layout'>
    <Quiz></Quiz>
    </div>
  );
}

export default App;

Copy the code

Create the Exam directory in the project SRC directory, and create quiz. js in the Exam directory

The Quiz component is defined as follows: quiz.js, introducing the start page component Toggle.

import React, { useState } from "react";
import { Toggle } from "./Toggle";
export const Quiz = () => {
  const [questionData, setQuestionData] = useState([]);
  const questions = questionData.map(({ question }) => [question]);
  const answers = questionData.map(({ incorrect_answers, correct_answer }) =>
    [correct_answer, incorrect_answers].flat()
  );
  return (
    <>
      <Toggle
        setQuestionData={setQuestionData}
      />
    </>
  );
};
Copy the code

Toggle.js, click the start button, access the remote interface through AXIos, and get the question and answer.

import React from "react";
import axios from "axios";
import ToggleHeader from "./ToggleHeader";
import {
  Button,
  Form,
} from "reactstrap";

export const Toggle = ({
  setQuestionData,
}) => {
  const getData = async () => {
    try {
      const incomingData = await axios.get(
        `https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=multiple`
      );
      setQuestionData(incomingData.data.results); } catch (err) { console.error(err); }};return (
    <>
      <ToggleHeader />
      <Form
        onSubmit={(e) => {
          e.preventDefault();
          getData();
        }}
      >
        <Button color="primary"</Button> </Form> </>); };Copy the code

ToggleHeader.js

import React from "react";
import { Jumbotron, Container} from "reactstrap";

export default function ToggleHeader() {
  return (
    <Jumbotron fluid>
      <Container fluid>
        <h1 className="display-4"</h1> </Container> </Jumbotron>); }Copy the code

opentdb.com/api.php Interface return…

{
	"response_code": 0."results": [{
		"category": "Science: Computers"."type": "multiple"."difficulty": "easy"."question": "The numbering system with a radix of 16 is more commonly referred to as "."correct_answer": "Hexidecimal"."incorrect_answers": ["Binary"."Duodecimal"."Octal"] {},"category": "Science: Computers"."type": "multiple"."difficulty": "easy"."question": "This mobile OS held the largest market share in 2012."."correct_answer": "iOS"."incorrect_answers": ["Android"."BlackBerry"."Symbian"] {},"category": "Science: Computers"."type": "multiple"."difficulty": "easy"."question": "How many values can a single byte represent?"."correct_answer": "256"."incorrect_answers": ["8"."1"."1024"] {},"category": "Science: Computers"."type": "multiple"."difficulty": "easy"."question": "In computing, what does MIDI stand for?"."correct_answer": "Musical Instrument Digital Interface"."incorrect_answers": ["Musical Interface of Digital Instruments"."Modular Interface of Digital Instruments"."Musical Instrument Data Interface"] {},"category": "Science: Computers"."type": "multiple"."difficulty": "easy"."question": "In computing, what does LAN stand for?"."correct_answer": "Local Area Network"."incorrect_answers": ["Long Antenna Node"."Light Access Node"."Land Address Navigation"]]}}Copy the code

Program running effect:

2. Problem display page

Quiz.js, added toggleView variable to switch views.

  const [toggleView, setToggleView] = useState(true);
Copy the code

Quiz.js, with the Question and QuestionHeader components, see below.

import { Question } from "./Question";
import { Jumbotron } from "reactstrap";
import QuestionHeader from "./QuestionHeader"; .export const Quiz = () => {
  var [index, setIndex] = useState(0);
  const [questionData, setQuestionData] = useState([]); .return (
    <>
      {toggleView && (
        <Toggle
          setIndex={setIndex}
          setQuestionData={setQuestionData}
          setToggleView={setToggleView} /> )} {! toggleView && ( <Jumbotron> <QuestionHeadersetToggleView={setToggleView}
            />
            <Question question={questions[index]} />
          </Jumbotron>
        )}
    </>
  );
Copy the code

Use index to control the subject index

var [index, setIndex] = useState(0);
Copy the code

Modify Toggle. Js to get remote data by setToggleView(false); Switch views.

export const Toggle = ({
  setQuestionData,
  setToggleView,
  setIndex,
}) => {
  
...

  return (
    <>
      <ToggleHeader />
      <Form
        onSubmit={(e) => {
          e.preventDefault();
          getData();
          setToggleView(false);
          setIndex(0);
        }}
      >
        <Button color="primary"</Button> </Form> </>); };Copy the code

Questionheader. js code: Again, click the back to home button setToggleView(true) to switch views.

import React from "react";
import { Button } from "reactstrap";
export default function QuestionHeader({ setToggleView, category }) {
  return (
    <>
      <Button color="link" onClick={() => setToggleView(true</Button> </>); }Copy the code

The question.js code takes the Question object passed by the parent component and displays it. He. Decode is to escape special characters in the string.

import React from "react";
import he from "he";
export const Question = ({ question }) => {
  // he is a oddly named library that decodes html into string values

  var decode = he.decode(String(question));

  return (
    <div>
      <hr className="my-2" />
      <h1 className="display-5">
        {decode}
      </h1>
      <hr className="my-2" />
      <br />
    </div>
  );
};

Copy the code

Program run effect: home page

The current project directory structure is:

3. Load the waiting animation

New LoadingSpin. Js

import React from "react";
import { Spinner } from "reactstrap";
export default function LoadingSpin() {
  return (
    <>
      <Spinner type="grow" color="primary" />
      <Spinner type="grow" color="secondary" />
      <Spinner type="grow" color="success" />
      <Spinner type="grow" color="danger"/ > < / a >); }Copy the code

Modify the quizzes. Js


import LoadingSpin from "./LoadingSpin";

export const Quiz = () => {

  const [isLoading, setLoading] = useState(false);


  return (
    <>
      {toggleView && (
        <Toggle
          ...
          setLoading={setLoading} /> )} {! toggleView && (isLoading ? ( <LoadingSpin /> ) : ( ... ) )} < / a >); };Copy the code

Modify the Toggle. Js



export const Toggle = ({
...
  setLoading,
}) => {
  const getData = async () => {
    try {
      setLoading(true);
      const incomingData = await axios.get(
        `https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=multiple`
      );
      setQuestionData(incomingData.data.results);
      setLoading(false); } catch (err) { console.error(err); }}; . };Copy the code

Operation effect:

4. Implement the next function

Add answer.js. The user clicks the next question button to modify index, triggering the refresh of the main interface and displaying the next question:

import React from "react";
import { Button } from "reactstrap";

export const Answer = ({ setIndex, index }) => {
  function answerResult() {
    setIndex(index + 1);
  }

  return (
    <Button className="ansButton"OnClick ={answerResult}> 下一题 </Button>); };Copy the code

Modify quiz.js and add Answer component:

import { Answer } from "./Answer"; . {! toggleView && (isLoading ? ( <LoadingSpin /> ) : ( <Jumbotron> ... <AnswersetIndex={setIndex}
            index={index}
            />
          </Jumbotron>

        ))}
Copy the code

Operation effect:


5. Display of implementation options

New AnswerList. Js. The list of options passed in through the property ANSWERS needs to be shuffled.

import React from "react";
import { Answer } from "./Answer";

export const AnswerList = ({ answers, index, setIndex }) => {
  if (answers) var correctAns = answers[0];

  const shuffle = (array) => {
    returnArray.sort (() => math.random () -0.5); }; const arrayCheck = (arg) => {return Array.isArray(arg) ? arg : [];
  };

  return (
    <>
      {shuffle(arrayCheck(answers)).map((text,ind) => (
        <Answer
          text={text}
          correct={correctAns}
          setIndex={setIndex}
          index={index}
          key={ind}
        />
      ))}
    </>
  );
};

Copy the code

Modify the Answer. Js

import React from "react";
import he from "he";
import { Button } from "reactstrap";
export const Answer = ({ text, correct, setIndex, index }) => {
  function answerResult() {
    setIndex(index + 1);
  }


  var decode = he.decode(String(text));

  return (
    <Button className="ansButton" onClick={answerResult}>
      {decode}
    </Button>
  );
};

Copy the code

Modify the quizzes. Js

// import { Answer } from "./Answer";
import { AnswerList } from "./AnswerList";


export const Quiz = () => {
...
  return (
    <>
      ...
      {!toggleView &&
        (isLoading ? (
          <LoadingSpin />
        ) : 
        (
        ...
            <AnswerList
              answers={answers[index]}
              index={index}
              setIndex={setIndex}
            />
          </Jumbotron>

        ))}
    </>
  );
};

Copy the code

Operation effect:

6. Record user scores

Modify quiz.js, add setResult, and pass it to AnswerList


export const Quiz = () => {
 
  var [result, setResult] = useState(null); .return (
    <>
    ...
      {!toggleView &&
        (isLoading ? (
          <LoadingSpin />
        ) : 
        (
          <Jumbotron>
          ...
            <AnswerList
              answers={answers[index]}
              index={index}
              setIndex={setIndex}
              setResult={setResult}
            />
          </Jumbotron>

        ))}
    </>
  );
};

Copy the code

Modify answerlist. js and pass setResult

import React from "react";
import { Answer } from "./Answer";

export const AnswerList = ({ answers, index,setResult, setIndex }) => {
...

  return (
    <>
      {shuffle(arrayCheck(answers)).map((text,ind) => (
        <Answer
          text={text}
          correct={correctAns}
          setIndex={setIndex}
          setResult={setResult}
          index={index}
          key={ind}
        />
      ))}
    </>
  );
};

Copy the code

To modify answer.js, the user clicks options and calls back setResult to inform the Quiz component whether the selection is correct or wrong.

import React from "react";
import { Button } from "reactstrap";
import he from 'he'


export const Answer = ({ text, correct, setResult,setIndex, index }) => {
  function answerResult() {
    setIndex(index + 1);
    correct === text ? setResult(true) : setResult(false);
  }

  var decode = he.decode(String(text));

  return (
    <Button className="ansButton" onClick={answerResult}>
      {decode}
    </Button>
  );
};

Copy the code

Fix quiz. js and put a hidden GameOver component. Whenever the index changes, the useEffect code in GameOver will be triggered and the cumulative number of correct answers will be setRight.


import GameOver from "./GameOver";

export const Quiz = () => {

  const [right, setRight] = useState(0);
  const [gameIsOver, setGameOver] = useState(false);


  return (
   <>
      {toggleView && (
        <Toggle
          setIndex={setIndex}
          setQuestionData={setQuestionData}
          setToggleView={setToggleView}
          setLoading={setLoading} /> )} {! toggleView && (isLoading ? ( <LoadingSpin /> ) : ( <Jumbotron> <QuestionHeadersetToggleView={setToggleView}
              />
              <Question question={questions[index]} />
              <AnswerList
                answers={answers[index]}
                index={index}
                setIndex={setIndex}
                setResult={setResult}
              />
            </Jumbotron>
      ))}
      <GameOver
        right={right}
        setRight={setRight}
        quizLength={questions.length}
        setGameOver={setGameOver}
        result={result}
        index={index}
      />
    </>
  );
};

Copy the code

GameOver. Js component added. SetGameOver (true) sets game end and displays user score when index === quizLength && index.

import React, { useEffect } from "react";

export default function GameOver({
  right,
  setRight,
  setGameOver,
  index,
  quizLength,
  result,
}) {
  useEffect(() => {
    if (result === true) {
      setRight(right + 1);
    } 

    if (index === quizLength && index) {
      setGameOver(true);
    }
  }, [index]);

  return <div></div>;
}
Copy the code

7. When the game is over, show the user’s score

The new “js

import React from "react";

export const ScoreBoard = ({ finalScore, right }) => {
  // if index === 0 then right === 0 --> this way when index is reset in toggle so is right answers
  const scoreFormatted = score => {
    if (score === 1) {
      return 100;
    } else if (score === 0) {
      return 0;
    } else {
      returnscore.toFixed(2) * 100; }}return (
    <>
      <>
        <h1 className="display-4">Correct Answers: {right}</h1>
        <hr className="my-2" />

        <h1 className="display-4">
          Final Score: %{scoreFormatted(finalScore)}
        </h1>

        <hr className="my-2"/> </> <p> Thank you for using </p> </>); };Copy the code

ScoreHeader.js

import React from "react";
import { Button } from "reactstrap";
export default function ScoreHeader({ setGameOver, setToggleView }) {
  return (
    <Button
      color="link"
      onClick={() => {
        setGameOver(false);
        setToggleView(true); </Button>); }Copy the code

Modify quiz.js to display the score page when the gameIsOver variable is true.

import { ScoreBoard } from "./ScoreBoard";
import ScoreHeader from "./ScoreHeader";

export const Quiz = () => {

...

  return(< > {! toggleView && ! gameIsOver && (isLoading ? ( <LoadingSpin /> ) : ( ... ) )} {gameIsOver && ( <Jumbotron> <ScoreHeadersetToggleView={setToggleView}
            setGameOver={setGameOver} /> <ScoreBoard right={right} finalScore={right / index} /> </Jumbotron> )} ... < / a >); };Copy the code

The last

If you think John bean’s article is helpful to you, and don’t want to miss John Bean’s future more and better technical training, please