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

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

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

import React, { useEffect, useState } from 'react';
import { makeStyles } from '@mui/styles';
import { Container, Typography, Button, Checkbox, Dialog, DialogTitle, DialogContent, DialogActions, } from '@mui/material';

const useStyles = makeStyles((theme) => ({
  root: {
    background: '#ADD8E6',
    minHeight: '100vh',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
  appContainer: {
    background: '#fff',
    borderRadius: 10,
    padding: 30,
  },
  delimiter: {
    color: '#001e4d',
    borderBottom: '1px solid #333',
    paddingBottom: 13,
    marginBottom: 8,
  },
  question: {
    fontSize: 18,
    color: '#001e4d',
    fontWeight: 600,
    paddingTop: 3,
  },
  answerContainer: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'flex-start',
    marginTop: 20,
  },
  answerText: {
    fontSize: 18,
    color: '#001e4d',
    fontWeight: 500,
  },
  answerCheckbox: {
    marginBottom: 10,
  },
  answerButton: {
    background: '#fff',
    color: '#222',
    fontWeight: 500,
    width: '100%',
    border: '1px solid #222',
    padding: 10,
    margin: '10px 0',
    textAlign: 'left',
    borderRadius: 4,
    cursor: 'pointer',
    '&:hover:not($displayed)': {
      background: '#222',
      color: '#fff',
    },
    '&:disabled': {
      cursor: 'no-drop',
    },
  },
  nextButton: {
    background: '#001e4d',
    color: '#fff',
    fontWeight: 500,
    width: 120,
    border: 0,
    padding: 10,
    margin: '20px 0 0 auto',
    borderRadius: 4,
    cursor: 'pointer',
    display: 'none',
  },
  previousButton: {
    backgroundColor: '#ffffff',
    color: '#222',
    fontWeight: 500,
  },
  timer: {
    marginLeft: '10rem',
    marginTop: '0.5rem',
  },
  redTimer: {
    color: 'red',
  },
}));

  
const questions = [
  {
    question: "What is Lorem Ipsum?",
    selectedAnswerIndex: -1,
    answers: [
      { 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 },
      { text: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", correct: true },
      { text: "Lorem Ipsum", correct: false },
      { text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", correct: false },
    ]
  },
  {
    question: "What is Lorem Ipsum?",
    answers: [
      { text: "1", correct: false },
      { text: "2", correct: true },
      { text: "3", correct: false },
      { text: "4", correct: false },
    ]
  },
  {
    question: "What is Lorem Ipsum?",
    answers: [
      { text: "1", correct: false },
      { text: "2", correct: true },
      { text: "3", correct: false },
      { text: "4", correct: false },
    ]
  },
];

const JoinQuiz = () => {
  const classes = useStyles();
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  const [score, setScore] = useState(0);
  const [selectedAnswerIndex, setSelectedAnswerIndex] = useState(-1);
  const [timer, setTimer] = useState(5);
  const [showDialog, setShowDialog] = useState(false);
  const [dialogMessage, setDialogMessage] = useState('');
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [userAnswers, setUserAnswers] = useState(new Array(questions.length).fill(-1));

  const currentQuestion = questions[currentQuestionIndex];

  useEffect(() => {
    let timerId;
    if (!isSubmitted) { // Only start the timer if quiz is not submitted
      timerId = setInterval(() => {
        setTimer((prevTimer) => {
          if (prevTimer === 0) {
            clearInterval(timerId);
            handleQuizSubmission(); // Automatically submit quiz when timer reaches 0
            return 0;
          }
          return prevTimer - 1;
        });
      }, 1000);
    }
    return () => clearInterval(timerId); // Clear the timer when component unmounts or quiz is submitted
  }, [isSubmitted]);

  const handleNextQuestion = () => {
    const nextQuestionIndex = currentQuestionIndex + 1;
    if (nextQuestionIndex < questions.length) {
      setCurrentQuestionIndex(nextQuestionIndex);
      setSelectedAnswerIndex(-1); // Reset selected answer
    } else {
      handleQuizSubmission();
    }
  };

  const handlePreviousQuestion = () => {
    const previousQuestionIndex = currentQuestionIndex - 1;
    if (previousQuestionIndex >= 0) {
      setCurrentQuestionIndex(previousQuestionIndex);
    }
  };

  const handleQuizSubmission = () => {
    let totalScore = 0;
    for (let i = 0; i < questions.length; i++) {
      const question = questions[i];
      const userAnswerIndex = userAnswers[i];
      if (userAnswerIndex !== -1) {
        if (question.answers[userAnswerIndex]?.correct) {
          totalScore += 1;
        }
      }
    }
    const scorePercentage = (totalScore / questions.length) * 100;
    const message = `Quiz submitted! Score: ${totalScore}/${questions.length} (${scorePercentage}%)`;
    setShowDialog(true);
    setDialogMessage(message);
    setIsSubmitted(true);
  };
    
  const handleAnswerSelect = (index, correct) => {
    if (!isSubmitted) {
      setSelectedAnswerIndex(index);
      const updatedUserAnswers = [...userAnswers];
      updatedUserAnswers[currentQuestionIndex] = index;
      setUserAnswers(updatedUserAnswers);
      if (correct) {
        setScore(score + 1);
      }
    }
  };
  
  useEffect(() => {
    // Update the selected answer index when the current question changes
    if (currentQuestionIndex >= 0) {
      setSelectedAnswerIndex(userAnswers[currentQuestionIndex]);
    }
  }, [currentQuestionIndex, userAnswers]);

  const handleDialogClose = () => {
    setShowDialog(false);
  };

  const formatTime = (seconds) => {
    const minutes = Math.floor(seconds / 60);
    const secondsRemaining = seconds % 60;
    return `${minutes.toString().padStart(2, '0')}:${secondsRemaining.toString().padStart(2, '0')}`;
  };

  return (
    <div className={classes.root}>
      <Container className={classes.appContainer} maxWidth="lg">
        <div className={classes.quiz}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <Typography variant="h4" component="h1" >
              Simple Quiz
            </Typography>
            <Typography
              variant="h6"
              className={`${classes.timer} ${timer <= 120 && !isSubmitted ? classes.redTimer : ''}`}
            >
              Timer: {formatTime(timer)}
            </Typography>
          </div>
          <div className={classes.delimiter}></div>
          <Typography variant="h3" className={classes.question}>
            {currentQuestion.question}
          </Typography>
          <div className={classes.answerContainer}>
            {currentQuestion.answers.map((answer, index) => (
              <div key={index} className={classes.answerText}>
                <Checkbox
                  className={classes.answerCheckbox}
                  checked={selectedAnswerIndex === index}
                  onChange={() => handleAnswerSelect(index, answer.correct)}
                  disabled={isSubmitted} // Disable checkboxes when quiz is submitted
                />
                {String.fromCharCode(97 + index)})&nbsp; {answer.text}
              </div>
            ))}
          </div>
          <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
            {currentQuestionIndex > 0 && (
            <Button
              sx={{ marginTop: '0.3rem', marginBottom: '0.3rem', marginRight: '1rem' }}
              style={{ backgroundColor: '#ffffff', color: '#222', fontWeight: 500 }}
              className={classes.previousButton}
              variant="contained"
              onClick={handlePreviousQuestion}
              disabled={isSubmitted}
            >
              Previous
            </Button>
            )}
            <Button
              sx={{ marginTop: '0.3rem', marginBottom: '0.3rem', marginLeft: '4rem' }}
              style={{ backgroundColor: '#4c9deb' }}
              className={classes.nextButton}
              variant="contained"
              color="primary"
              id={currentQuestionIndex === questions.length - 1 ? 'Submit-btn' : 'Next-btn'}
              onClick={handleNextQuestion}
              disabled={selectedAnswerIndex === -1 || isSubmitted} // Disable button when quiz is submitted
            >
              {currentQuestionIndex === questions.length - 1 ? 'Submit' : 'Next'}
            </Button>
            <Dialog open={showDialog} onClose={handleDialogClose}>
              <DialogTitle>Quiz Results</DialogTitle>
              <DialogContent className={classes.dialogContent}>
                <Typography variant="h6" gutterBottom>
                  {dialogMessage}
                </Typography>
                <Typography variant="body1" gutterBottom>
                  Thank you for taking the quiz!
                </Typography>
              </DialogContent>
              <DialogActions>
                <Button onClick={handleDialogClose} color="primary" variant="contained">
                  Close
                </Button>
              </DialogActions>
            </Dialog>
          </div>
        </div>
      </Container>
    </div>
  );
  
};

export default JoinQuiz;

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

zxlwwiss

zxlwwiss1#

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

useEffect(() => {
        let timerId;
        if (!isSubmitted) { // Only start the timer if quiz is not submitted
          timerId = setInterval(() => {
            setTimer((prevTimer) => {
              if (prevTimer === 0) {
                clearInterval(timerId);

                setUserAnswers((answers) => {
                  handleQuizSubmission(answers); // Automatically submit quiz when timer reaches 0
                  return answers
                })
                return 0;
              }
              return prevTimer - 1;
            });
          }, 1000);
        }
        return () => clearInterval(timerId); // Clear the timer when component unmounts or quiz is submitted
      }, [isSubmitted]);

  const handleQuizSubmission = (answers = userAnswers) => {
    let totalScore = 0;
    for (let i = 0; i < questions.length; i++) {
      const question = questions[i];
      const userAnswerIndex = answers[i];
      if (userAnswerIndex !== -1) {
        if (question.answers[userAnswerIndex]?.correct) {
          totalScore += 1;
        }
      }
    }
    const scorePercentage = (totalScore / questions.length) * 100;
    const message = `Quiz submitted! Score: ${totalScore}/${questions.length} (${scorePercentage}%)`;
    setShowDialog(true);
    setDialogMessage(message);
    setIsSubmitted(true);
  };

相关问题