javascript 在尝试保存用户为React中制作的测验应用程序选择的答案的状态时非常卡住

wyyhbhjk  于 2022-12-10  发布在  Java
关注(0)|答案(1)|浏览(120)

我一直在尝试使用React制作一个测验应用程序,作为课程项目的一部分,我真的很难保存用户选择的答案的状态。
从API返回的数据显示由一组问题和每个问题的一组答案组成的数据。
我对如何在问题中循环答案数组感到困惑,特别是针对每个答案的id和isSelected布尔值,以便我可以针对这些ID并使用条件逻辑,当用户选择答案按钮时,它将触发isSelected布尔值为true并更改按钮的背景颜色。
这显示了我的数据数组,其中包含问题和答案选择的数组,沿着用于触发按钮保持状态的布尔值:

export default function QuizList(props) {
  const [quiz, setQuiz] = React.useState([]);

  React.useEffect(() => {
    /* This function turns HTML element entities into normal words */
    function decodeHtml(html) {
      const txt = document.createElement("textarea");
      txt.innerHTML = html;
      return txt.value;
    }

    fetch(
      "https://opentdb.com/api.php?amount=5&category=9&difficulty=medium&type=multiple"
    )
      .then((res) => res.json())
      .then((data) => {
        const dataArray = data.results;
        const newDataArray = [];
        dataArray.map((item) => {
          return newDataArray.push({
            question: decodeHtml(item.question),

            correct: decodeHtml(item.correct_answer),

            choices: [
              {
                choice: decodeHtml(item.correct_answer),
                isSelected: false,
                id: nanoid(),
              },
              {
                choice: decodeHtml(item.incorrect_answers[0]),
                isSelected: false,
                id: nanoid(),
              },
              {
                choice: decodeHtml(item.incorrect_answers[1]),
                isSelected: false,
                id: nanoid(),
              },
              {
                choice: decodeHtml(item.incorrect_answers[2]),
                isSelected: false,
                id: nanoid(),
              },
            ].sort(() => 0.5 - Math.random()),
            id: nanoid(),
          });
        });
        return setQuiz(newDataArray);
      });
  }, []);

下面是保存所选答案的函数,其中包含要呈现的组件:

function holdAnswer(id) {
    setQuiz((oldQuiz) =>
      oldQuiz.map((quiz) => {
        return quiz.choices.map((choice) => {
          return choice.id === id
            ? { ...choice, isSelected: !choice.isSelected }
            : choice;
        });
      })
    );
  }

  const quizItemComponents = quiz.map((item) => {
    return (
      <QuizItem
        key={item.id}
        question={item.question}
        choices={item.choices}
        holdAnswer={() =>
          holdAnswer(item.choices.forEach((choice) => choice.id))
        }
      />
    );
  });

  return (
    <Card className={classes.quizlist}>
      {quizItemComponents}
      <Button>Check Answers</Button>
    </Card>
  );
}

此外,下面的代码显示了各个测验组件将包含的内容以及其中的条件逻辑:

export default function QuizItem(props) {
  const isSelected = props.choices.forEach(choice => choice.isSelected)

  const styles = {
    backgroundColor: isSelected ? "#D6DBF5" : "white",
  };

  return (
    <div>
      <div key={props.id} className={classes.quizlist__quizitem}>
        <h3 className={classes.quizitem__h3}>{props.question}</h3>
        {props.choices.map((choice) => {
          return (
            <AnswerButton
              key={choice.id}
              onClick={props.holdAnswer}
              style={styles}
            >
              {choice.choice}
            </AnswerButton>
          );
        })}
      </div>
    </div>
  );
}

下面是自定义应答按钮的代码:

import classes from "./AnswerButton.module.css";

export default function AnswerButton(props) {
  return (
    <button
      className={classes.answerbutton}
      type={props.type || "button"}
      onClick={props.onClick}
      style={props.style}
      name={props.name}
    >
      {props.children}
    </button>
  );
}

我尝试过使用.forEach或.map()循环遍历答案数组以指向id和isSelected值,但最后都出现了错误。我尝试过很多其他方法,通过移动对象,但都没有效果。我不确定我是否没有正确地循环遍历答案数组,或者我是否需要其他方法来循环遍历它,或者在正确的区域插入适当的循环。

g6baxovj

g6baxovj1#

在第二个块代码中,setQuiz似乎将每个quiz设置为oldQuiz.map()中的唯一choices,可能预期返回值应该是{...quiz, choices}

function holdAnswer(id) {
  setQuiz((oldQuiz) =>
    oldQuiz.map((quiz) => {
      // 👇 Changed here
      return {
        ...quiz,
        choices: quiz.choices.map((choice) => {
          return choice.id === id
            ? { ...choice, isSelected: !choice.isSelected }
            : choice;
        }),
      };
    })
  );
}

另外,holdAnswer(id)所需的id似乎是choice.id,所以QuizItem的预期行为可能只是将此函数作为prop传递,并让choice提供其id

const quizItemComponents = quiz.map((item) => {
  return (
    <QuizItem
      key={item.id}
      question={item.question}
      choices={item.choices}
      // 👇 Changed here
      holdAnswer={holdAnswer}
    />
  );
});

return (
  <Card className={classes.quizlist}>
    {quizItemComponents}
    <Button>Check Answers</Button>
  </Card>
);
}

然后在第三个代码块中,styles的预期条件似乎基于每个choice.isSelected,因此可能可以将其移到props.choices.map()中。
同样在这里,每个choice可能应该在它们的onClick中传递id,以便holdAnswer使用,因为AnswerButton似乎没有访问此id的权限。

export default function QuizItem(props) {
  return (
    <div>
      <div key={props.id} className={classes.quizlist__quizitem}>
        <h3 className={classes.quizitem__h3}>{props.question}</h3>
        {props.choices.map((choice) => {
          // 👇 Changed here
          const styles = {
            backgroundColor: choice.isSelected ? "#D6DBF5" : "white",
          };
          return (
            <AnswerButton
              key={choice.id}
              // 👇 Changed here
              onClick={() => props.holdAnswer(choice.id)}
              style={styles}
            >
              {choice.choice}
            </AnswerButton>
          );
        })}
      </div>
    </div>
  );
}

可能还有其他需要解决的问题,如果不进行测试,可能很难发现,但希望这仍然有帮助。

相关问题