javascript 使用计时器为ReactJS测验实现自动提交功能:计时器停止后,我如何计算正确答案?

qvtsj1bj  于 2023-05-21  发布在  Java
关注(0)|答案(1)|浏览(141)

自动提交不工作,它应该如何。
如果我在最后手动提交测验,代码工作正常,但是如果时间用完,分数将始终是0/3,这是不正确的。

  1. import React, { useEffect, useState } from 'react';
  2. import { makeStyles } from '@mui/styles';
  3. import { Container, Typography, Button, Checkbox, Dialog, DialogTitle, DialogContent, DialogActions, } from '@mui/material';
  4. const useStyles = makeStyles((theme) => ({
  5. root: {
  6. background: '#ADD8E6',
  7. minHeight: '100vh',
  8. display: 'flex',
  9. alignItems: 'center',
  10. justifyContent: 'center',
  11. },
  12. appContainer: {
  13. background: '#fff',
  14. borderRadius: 10,
  15. padding: 30,
  16. },
  17. delimiter: {
  18. color: '#001e4d',
  19. borderBottom: '1px solid #333',
  20. paddingBottom: 13,
  21. marginBottom: 8,
  22. },
  23. question: {
  24. fontSize: 18,
  25. color: '#001e4d',
  26. fontWeight: 600,
  27. paddingTop: 3,
  28. },
  29. answerContainer: {
  30. display: 'flex',
  31. flexDirection: 'column',
  32. alignItems: 'flex-start',
  33. marginTop: 20,
  34. },
  35. answerText: {
  36. fontSize: 18,
  37. color: '#001e4d',
  38. fontWeight: 500,
  39. },
  40. answerCheckbox: {
  41. marginBottom: 10,
  42. },
  43. answerButton: {
  44. background: '#fff',
  45. color: '#222',
  46. fontWeight: 500,
  47. width: '100%',
  48. border: '1px solid #222',
  49. padding: 10,
  50. margin: '10px 0',
  51. textAlign: 'left',
  52. borderRadius: 4,
  53. cursor: 'pointer',
  54. '&:hover:not($displayed)': {
  55. background: '#222',
  56. color: '#fff',
  57. },
  58. '&:disabled': {
  59. cursor: 'no-drop',
  60. },
  61. },
  62. nextButton: {
  63. background: '#001e4d',
  64. color: '#fff',
  65. fontWeight: 500,
  66. width: 120,
  67. border: 0,
  68. padding: 10,
  69. margin: '20px 0 0 auto',
  70. borderRadius: 4,
  71. cursor: 'pointer',
  72. display: 'none',
  73. },
  74. previousButton: {
  75. backgroundColor: '#ffffff',
  76. color: '#222',
  77. fontWeight: 500,
  78. },
  79. timer: {
  80. marginLeft: '10rem',
  81. marginTop: '0.5rem',
  82. },
  83. redTimer: {
  84. color: 'red',
  85. },
  86. }));
  87. const questions = [
  88. {
  89. question: "What is Lorem Ipsum?",
  90. selectedAnswerIndex: -1,
  91. answers: [
  92. { text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", correct: false },
  93. { text: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", correct: true },
  94. { text: "Lorem Ipsum", correct: false },
  95. { text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", correct: false },
  96. ]
  97. },
  98. {
  99. question: "What is Lorem Ipsum?",
  100. answers: [
  101. { text: "1", correct: false },
  102. { text: "2", correct: true },
  103. { text: "3", correct: false },
  104. { text: "4", correct: false },
  105. ]
  106. },
  107. {
  108. question: "What is Lorem Ipsum?",
  109. answers: [
  110. { text: "1", correct: false },
  111. { text: "2", correct: true },
  112. { text: "3", correct: false },
  113. { text: "4", correct: false },
  114. ]
  115. },
  116. ];
  117. const JoinQuiz = () => {
  118. const classes = useStyles();
  119. const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  120. const [score, setScore] = useState(0);
  121. const [selectedAnswerIndex, setSelectedAnswerIndex] = useState(-1);
  122. const [timer, setTimer] = useState(5);
  123. const [showDialog, setShowDialog] = useState(false);
  124. const [dialogMessage, setDialogMessage] = useState('');
  125. const [isSubmitted, setIsSubmitted] = useState(false);
  126. const [userAnswers, setUserAnswers] = useState(new Array(questions.length).fill(-1));
  127. const currentQuestion = questions[currentQuestionIndex];
  128. useEffect(() => {
  129. let timerId;
  130. if (!isSubmitted) { // Only start the timer if quiz is not submitted
  131. timerId = setInterval(() => {
  132. setTimer((prevTimer) => {
  133. if (prevTimer === 0) {
  134. clearInterval(timerId);
  135. handleQuizSubmission(); // Automatically submit quiz when timer reaches 0
  136. return 0;
  137. }
  138. return prevTimer - 1;
  139. });
  140. }, 1000);
  141. }
  142. return () => clearInterval(timerId); // Clear the timer when component unmounts or quiz is submitted
  143. }, [isSubmitted]);
  144. const handleNextQuestion = () => {
  145. const nextQuestionIndex = currentQuestionIndex + 1;
  146. if (nextQuestionIndex < questions.length) {
  147. setCurrentQuestionIndex(nextQuestionIndex);
  148. setSelectedAnswerIndex(-1); // Reset selected answer
  149. } else {
  150. handleQuizSubmission();
  151. }
  152. };
  153. const handlePreviousQuestion = () => {
  154. const previousQuestionIndex = currentQuestionIndex - 1;
  155. if (previousQuestionIndex >= 0) {
  156. setCurrentQuestionIndex(previousQuestionIndex);
  157. }
  158. };
  159. const handleQuizSubmission = () => {
  160. let totalScore = 0;
  161. for (let i = 0; i < questions.length; i++) {
  162. const question = questions[i];
  163. const userAnswerIndex = userAnswers[i];
  164. if (userAnswerIndex !== -1) {
  165. if (question.answers[userAnswerIndex]?.correct) {
  166. totalScore += 1;
  167. }
  168. }
  169. }
  170. const scorePercentage = (totalScore / questions.length) * 100;
  171. const message = `Quiz submitted! Score: ${totalScore}/${questions.length} (${scorePercentage}%)`;
  172. setShowDialog(true);
  173. setDialogMessage(message);
  174. setIsSubmitted(true);
  175. };
  176. const handleAnswerSelect = (index, correct) => {
  177. if (!isSubmitted) {
  178. setSelectedAnswerIndex(index);
  179. const updatedUserAnswers = [...userAnswers];
  180. updatedUserAnswers[currentQuestionIndex] = index;
  181. setUserAnswers(updatedUserAnswers);
  182. if (correct) {
  183. setScore(score + 1);
  184. }
  185. }
  186. };
  187. useEffect(() => {
  188. // Update the selected answer index when the current question changes
  189. if (currentQuestionIndex >= 0) {
  190. setSelectedAnswerIndex(userAnswers[currentQuestionIndex]);
  191. }
  192. }, [currentQuestionIndex, userAnswers]);
  193. const handleDialogClose = () => {
  194. setShowDialog(false);
  195. };
  196. const formatTime = (seconds) => {
  197. const minutes = Math.floor(seconds / 60);
  198. const secondsRemaining = seconds % 60;
  199. return `${minutes.toString().padStart(2, '0')}:${secondsRemaining.toString().padStart(2, '0')}`;
  200. };
  201. return (
  202. <div className={classes.root}>
  203. <Container className={classes.appContainer} maxWidth="lg">
  204. <div className={classes.quiz}>
  205. <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
  206. <Typography variant="h4" component="h1" >
  207. Simple Quiz
  208. </Typography>
  209. <Typography
  210. variant="h6"
  211. className={`${classes.timer} ${timer <= 120 && !isSubmitted ? classes.redTimer : ''}`}
  212. >
  213. Timer: {formatTime(timer)}
  214. </Typography>
  215. </div>
  216. <div className={classes.delimiter}></div>
  217. <Typography variant="h3" className={classes.question}>
  218. {currentQuestion.question}
  219. </Typography>
  220. <div className={classes.answerContainer}>
  221. {currentQuestion.answers.map((answer, index) => (
  222. <div key={index} className={classes.answerText}>
  223. <Checkbox
  224. className={classes.answerCheckbox}
  225. checked={selectedAnswerIndex === index}
  226. onChange={() => handleAnswerSelect(index, answer.correct)}
  227. disabled={isSubmitted} // Disable checkboxes when quiz is submitted
  228. />
  229. {String.fromCharCode(97 + index)})&nbsp; {answer.text}
  230. </div>
  231. ))}
  232. </div>
  233. <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
  234. {currentQuestionIndex > 0 && (
  235. <Button
  236. sx={{ marginTop: '0.3rem', marginBottom: '0.3rem', marginRight: '1rem' }}
  237. style={{ backgroundColor: '#ffffff', color: '#222', fontWeight: 500 }}
  238. className={classes.previousButton}
  239. variant="contained"
  240. onClick={handlePreviousQuestion}
  241. disabled={isSubmitted}
  242. >
  243. Previous
  244. </Button>
  245. )}
  246. <Button
  247. sx={{ marginTop: '0.3rem', marginBottom: '0.3rem', marginLeft: '4rem' }}
  248. style={{ backgroundColor: '#4c9deb' }}
  249. className={classes.nextButton}
  250. variant="contained"
  251. color="primary"
  252. id={currentQuestionIndex === questions.length - 1 ? 'Submit-btn' : 'Next-btn'}
  253. onClick={handleNextQuestion}
  254. disabled={selectedAnswerIndex === -1 || isSubmitted} // Disable button when quiz is submitted
  255. >
  256. {currentQuestionIndex === questions.length - 1 ? 'Submit' : 'Next'}
  257. </Button>
  258. <Dialog open={showDialog} onClose={handleDialogClose}>
  259. <DialogTitle>Quiz Results</DialogTitle>
  260. <DialogContent className={classes.dialogContent}>
  261. <Typography variant="h6" gutterBottom>
  262. {dialogMessage}
  263. </Typography>
  264. <Typography variant="body1" gutterBottom>
  265. Thank you for taking the quiz!
  266. </Typography>
  267. </DialogContent>
  268. <DialogActions>
  269. <Button onClick={handleDialogClose} color="primary" variant="contained">
  270. Close
  271. </Button>
  272. </DialogActions>
  273. </Dialog>
  274. </div>
  275. </div>
  276. </Container>
  277. </div>
  278. );
  279. };
  280. export default JoinQuiz;

我希望当时间结束时,到目前为止给出的答案将计入最终分数,未回答的问题将被视为不正确。

zxlwwiss

zxlwwiss1#

这是因为您还没有将userAnswers添加到useEffect的依赖项列表中。但是在将userAnswers添加到依赖列表之后,它不能像你预期的那样工作,因为每当userAnswers发生变化时,它就会被执行。
我认为这不是一个好的解决办法,但它可以解决你的问题。

  1. useEffect(() => {
  2. let timerId;
  3. if (!isSubmitted) { // Only start the timer if quiz is not submitted
  4. timerId = setInterval(() => {
  5. setTimer((prevTimer) => {
  6. if (prevTimer === 0) {
  7. clearInterval(timerId);
  8. setUserAnswers((answers) => {
  9. handleQuizSubmission(answers); // Automatically submit quiz when timer reaches 0
  10. return answers
  11. })
  12. return 0;
  13. }
  14. return prevTimer - 1;
  15. });
  16. }, 1000);
  17. }
  18. return () => clearInterval(timerId); // Clear the timer when component unmounts or quiz is submitted
  19. }, [isSubmitted]);
  20. const handleQuizSubmission = (answers = userAnswers) => {
  21. let totalScore = 0;
  22. for (let i = 0; i < questions.length; i++) {
  23. const question = questions[i];
  24. const userAnswerIndex = answers[i];
  25. if (userAnswerIndex !== -1) {
  26. if (question.answers[userAnswerIndex]?.correct) {
  27. totalScore += 1;
  28. }
  29. }
  30. }
  31. const scorePercentage = (totalScore / questions.length) * 100;
  32. const message = `Quiz submitted! Score: ${totalScore}/${questions.length} (${scorePercentage}%)`;
  33. setShowDialog(true);
  34. setDialogMessage(message);
  35. setIsSubmitted(true);
  36. };
展开查看全部

相关问题