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