首页 » 网站建设 » quizjsphp技巧_从0开始手把手教你运用React Hooks开拓答题App

quizjsphp技巧_从0开始手把手教你运用React Hooks开拓答题App

访客 2024-12-07 0

扫一扫用手机浏览

文章目录 [+]

视频加载中...

项目代码构造

quizjsphp技巧_从0开始手把手教你运用React Hooks开拓答题App

序言

React 框架的优雅不言而喻,组件化的编程思想使得React框架开拓的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐。
React Hooks 是 React 16.8 发布以来最吸引人的特性之一,它简化了原有代码的编写,是未来 React 运用的主流写法。

quizjsphp技巧_从0开始手把手教你运用React Hooks开拓答题App
(图片来自网络侵删)

本文通过一个实战小项目,手把手从零开始带领大家快速入门React Hooks。
本项目线上演示地址:

在本项目中,会用到以下知识点:

React 组件化设计思想React State 和 PropsReact 函数式组件的利用React Hooks useState 的利用React Hooks useEffect 的利用React 利用 Axios 要求远程接口获取问题及答案React 利用Bootstrap美化界面Hello React

(1)安装node.js 官网链接

(2)安装vscode 官网链接

(3)安装 creat-react-app 功能组件,该组件可以用来初始化一个项目, 即按照一定的目录构造,天生一个新项目。
打开cmd 窗口 输入:

npm install --g create-react-app npm install --g yarn

(-g 代表全局安装)

如果安装失落败或较慢。
须要换源,可以利用淘宝NPM镜像,设置方法为:

npm config set registry https://registry.npm.taobao.org

设置完成后,重新实行

npm install --g create-react-appnpm install --g yarn

(4)在你想创建项目的目录下 例如 D:/project/ 打开cmd命令 输入

create-react-app react-exam

去利用creat-react-app命令创建名字是react-exam的项目

安装完成后,移至新创建的目录并启动项目

cd react-examyarn start

一旦运行此命令,localhost:3000新的React运用程序将弹出一个新窗口。

项目目录构造

右键react-exam目录,利用vscode打开该目录。
react-exam项目目录中有一个/public和/src目录,以及node_modules,.gitignore,README.md,和package.json。

在目录/public中,主要文件是index.html,个中一行代码最主要

<div id="root"></div>

该div作为我们全体运用的挂载点

/src目录将包含我们所有的React代码。

要查看环境如何自动编译和更新您的React代码,请找到文件/src/App.js: 将个中的

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

修正为

<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > 和豆约翰 Learn React </a>

保存文件后,您会把稳到localhost:3000编译并刷新了新数据。

React-Exam项目实战1. 首页制作

1.安装项目依赖,在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", "axios": "^0.19.2", "bootstrap": "^4.5.0", "he": "^1.2.0", "react-loading": "^2.0.3", "reactstrap": "^8.4.1" },

实行命令:

yarn install

修正index.js,导入bootstrap样式

import "bootstrap/dist/css/bootstrap.min.css";

修正App.css代码

html { width: 80%; margin-left: 10%; margin-top: 2%;}.ansButton { margin-right: 4%; margin-top: 4%;}

修正App.js,引入Quiz组件

import React from 'react';import './App.css'import { Quiz } from './Exam/Quiz';function App() { return ( <div className = 'layout'> <Quiz></Quiz> </div> );}export default App;

在项目src目录下新增Exam目录,Exam目录中新建Quiz.js

Quiz组件的定义如下: Quiz.js,引入开始页面组件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} /> </> );};

Toggle.js,点击开始按钮,通过axios访问远程接口,得到题目及答案。

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> </> );};

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> );}

https://opentdb.com/api.php接口返回的json数据格式为

{"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"]}]}

程序运行效果:

当前项目目录构造为:

2. 问题展示页面

Quiz.js,新增toggleView变量用来切换视图。

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

Quiz.js,个中Question和QuestionHeader 组件,拜会后面。

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> <QuestionHeader setToggleView={setToggleView} /> <Question question={questions[index]} /> </Jumbotron> )} </> );

利用index掌握题目索引

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

修正Toggle.js 获取完远程数据,通过setToggleView(false);切换视图。

export const Toggle = ({ setQuestionData, setToggleView, setIndex,}) => { ... return ( <> <ToggleHeader /> <Form onSubmit={(e) => { e.preventDefault(); getData(); setToggleView(false); setIndex(0); }} > <Button color="primary">开始</Button> </Form> </> );};

QuestionHeader.js代码: 同样的,点击 返回顾页按钮 setToggleView(true),切换视图。

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

Question.js代码 接管父组件传过来的question工具,并显示。
个中he.decode是对字符串中的分外字符进行转义。

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> );};

程序运行效果: 首页

点击开始后,显示问题:

当前项目目录构造为:

3. 加载等待动画

新增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" /> </> );}

修正Quiz.js

import LoadingSpin from "./LoadingSpin";export const Quiz = () => { const [isLoading, setLoading] = useState(false); return ( <> {toggleView && ( <Toggle ... setLoading={setLoading} /> )} {!toggleView && (isLoading ? ( <LoadingSpin /> ) : ( ... ))} </> );};

修正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); } }; ...};

运行效果:

目前代码构造:

4. 实现下一题功能

新增Answer.js,用户点击下一题按钮,修正index,触发主界面刷新,显示下一题:

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> );};

修正Quiz.js,添加Answer组件:

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

运行效果:

点击下一题:

5. 实现选项展示

新增AnswerList.js。
通过属性answers传进来的选项列表,须要被打乱顺序(shuffle )

import React from "react";import { Answer } from "./Answer";export const AnswerList = ({ answers, index, setIndex }) => { if (answers) var correctAns = answers[0]; const shuffle = (array) => { return array.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} /> ))} </> );};

修正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> );};

修正Quiz.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> ))} </> );};

运行效果:

项目构造:

6. 记录用户成绩

修正quiz.js,添加setResult,并通报给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> ))} </> );};

修正AnswerList.js,通报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} /> ))} </> );};

修正Answer.js,用户点击选项,回调setResult,关照Quiz组件,本次选择是对是错。

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> );};

修正Quiz.js,放一个隐蔽的GameOver组件,每当index发生变革的时候,触发GameOver中的useEffect代码,累计用户答对题目的数目(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> <QuestionHeader setToggleView={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} /> </> );};

新增GameOver.js组件,当index === quizLength && index时,setGameOver(true)设置游戏结束,显示用户得分。

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>;}7. 游戏结束,展示用户得分

新增ScoreBoard.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 { return score.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>感激利用 </p> </> );};

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> );}​

修正Quiz.js,当gameIsOver 变量为true时,显示得分页面。

import { ScoreBoard } from "./ScoreBoard";import ScoreHeader from "./ScoreHeader";​export const Quiz = () => {​...​ return ( <> {!toggleView && !gameIsOver && (isLoading ? ( <LoadingSpin /> ) : ( ... ))} {gameIsOver && ( <Jumbotron> <ScoreHeader setToggleView={setToggleView} setGameOver={setGameOver} /> <ScoreBoard right={right} finalScore={right / index} /> </Jumbotron> )} ... </> );};​

标签:

相关文章