【问题标题】:Created a Quiz using React, trying to create bookmarking system where users can bookmark questions from quiz使用 React 创建了一个测验,尝试创建书签系统,用户可以在其中为测验中的问题添加书签
【发布时间】:2020-02-19 03:08:18
【问题描述】:

使用 React,我创建了一个测验,用户可以在其中提出问题并选择答案: https://codesandbox.io/s/quiz-1cf1m

我正在尝试添加书签功能,用户可以在其中“添加书签”他们想要稍后返回的问题。测验结束后,可以在结果摘要中显示他们收藏的问题列表(并希望单击以获取该特定问题)。

在我的问题组件中,我添加了 isBookMarked 设置为 false 和 bookmarkedQuestions 设置为一个空数组。然后创建了一个切换书签图标的 handleBookmark 函数。

class Question extends React.Component {
  state = {
    pick: false,
    correct: false,
    isBookmarked: false,
    bookmarkedQuestions: []
  };

  correctOrIncorrect = pick => {
    if (pick === this.state.pick) {
      return this.state.correct ? "correct" : "incorrect";
    } else if (
      pick === !this.state.correct &&
      this.props.currentQuestion.correctAnswer
    ) {
      return "correct";
    } else {
      return "clear";
    }
  };

  handleSelect = pick => {
    if (pick === this.props.currentQuestion.correctAnswer) {
      this.setState({ pick, correct: true });
    } else {
      this.setState({ pick });
    }
  };

  moveToNextQuestion = () => {
    this.setState({ pick: false, correct: false });
    this.props.nextQuestionHandler(this.state.correct);
  };

  handleBookmark = () => {
    console.log(this.props.currentQuestion);

    this.setState({
      isBookmarked: !this.state.isBookmarked
    });
  };

  render() {
    const { currentQuestion, shuffledAnswerChoices } = this.props;

    return (
      <div className={this.props.animation ? this.props.animation : null}>
        <span>
          <i
            id={currentQuestion}
            className={
              this.state.isBookmarked ? "fa fa-bookmark" : "fa fa-bookmark-o"
            }
            onClick={() => this.handleBookmark()}
          />
        </span>
        <p>{currentQuestion.text}</p>
        <ol type="A">
          {shuffledAnswerChoices.map((pick, idx) => {
            return (
              <li
                key={idx}
                className={this.state.pick ? this.correctOrIncorrect(pick) : null}
                onClick={() => this.handleSelect(pick)}
              >
                {pick}
              </li>
            );
          })}
        </ol>
        {this.state.pick && (
          <div>
            {this.state.correct ? (
              <p>
                <i>Correct!</i>
              </p>
            ) : (
              <p>
                <i>Incorrect</i>
              </p>
            )}
            <button className="next-btn" onClick={this.moveToNextQuestion}>
              Next
            </button>
          </div>
        )}
      </div>
    );
  }
}

export default Question;

我意识到使用当前的代码,当我为该图标添加书签时,除非我再次单击以取消添加书签,否则该图标会在整个测验过程中保持为书签。我添加了一个控制台日志,并且可以获取我正在处理的当前问题。我坚持只能为选定的问题添加书签,一旦用户转到下一个问题,它就会“重置”。我还尝试在添加书签时将问题推送到空的 bookmarkedQuestions 数组中,我想在测验结束时显示该数组(但刚刚意识到结果组件是同级而不是问题组件的子级,因此不能作为道具传下去……)。

那里有任何 React Pros 可以教我如何解决这个问题...?

从此书签系统扩展的附加问题:关于如何再次重复所有不正确的问题直到所有问题都得到正确回答的任何方法建议,摘要显示第一次正确回答了多少问题?

【问题讨论】:

    标签: javascript reactjs frontend


    【解决方案1】:

    绝对不是 React Pro,但我想我可以提供帮助!

    在我看来,我认为您应该将书签状态移至测验级别,以便它在测验期间持续存在。这意味着将一个函数传递给测验中的问题,以控制当前书签问题的状态。这也意味着“isBookmarked”标志也作为道具传递下来。

    这可能意味着创建的逻辑会使您的目标变得过于复杂。

    长示例(某些部分对于它需要做的事情过于复杂) - 随意不使用任何这些,但我进入它所以想添加它: https://codesandbox.io/s/quiz-x8wpv?fontsize=14&hidenavigation=1&theme=dark

    我弄乱了您的代码并创建了一个示例来说明它是如何工作的。我为书签选择的数据结构是一个对象,它具有测验的顶级键 [quizNumber],值是另一个对象,键是每个问题。然后会有一个布尔标志,指示是否已加入书签。为了实现这一点,为每个问题添加一个字段 id 会很有帮助

    为了避免存储大量数据,我从数据结构中省略了实际问题,因为它可以使用 quizNumber 和问题 ID 进行查找。

    所以我冒昧地更新了问题以匹配这种风格

      {
            qID: 1,
            text: "What is the capital of United States?",
            correctAnswer: "Washington, D.C.",
            incorrectAnswers: ["Philadelphia", "Annapolis", "New York City"]
          }
    

    因此,书签问题对象的结构可能是一个示例,

    {
     '0':{1:true},
     '2':{1:false, 2:true , 3:true}
    }
    

    此示例表示测验 0 的问题 1 以及测验 2 的问题 2 和 3 已添加书签。如果键不存在或为假,则可以假定该问题尚未添加书签。

    要设置这个,需要在测验级别创建一个函数。我创建的函数很可能对于它需要做的事情过于复杂,但如下

      bookmarkQuestion = () => {
        const { currentQuiz, numOfQuestions, quizQuestionBookmarks } = this.state;
        const { questions } = quizzes[currentQuiz];
        const { qID } = questions[numOfQuestions];
        // Can be simplified by creating a function to update nested values, or by using lodash
        // The destructuring is required so other parts of the object are not modified when updated deeper keys
        this.setState({
          quizQuestionBookmarks: {
            ...quizQuestionBookmarks,
            [currentQuiz]: {
              ...quizQuestionBookmarks[currentQuiz],
              [qID]: quizQuestionBookmarks[currentQuiz]
                ? !quizQuestionBookmarks[currentQuiz][qID]
                : true
            }
          }
        });
      };
    

    这个想法是现在可以在 currentQuizQuestions 上使用它来获取当前收藏的问题列表。

      getBookmarkedQuestions = () => {
        const { currentQuiz, quizQuestionBookmarks } = this.state;
        const { questions } = quizzes[currentQuiz];
        const boorkmarkedQuestions = questions.filter(question =>
          quizQuestionBookmarks[currentQuiz]
            ? quizQuestionBookmarks[currentQuiz][question.qID]
            : false
        );
        return boorkmarkedQuestions;
      };
    

    在我的示例中,我还将书签问题作为道具传递给结果页面,以演示如何将数据传递给它以供使用。

    【讨论】:

    • 还想就如何处理“从此书签系统扩展的其他问题”征求您的意见(顺便说一句,感谢您的书签建议)。我正在考虑在测验组件中添加 firstTry: true 和 repeatQuestions: [] 的状态字段...
    • 当您说“从此书签系统扩展的其他问题”时,您的意思是回到以前尝试过的问题吗?
    • 嗯...我想更像是附加功能?如果用户错误地回答了这个问题,那么最后应该再次问这个问题 - 直到用户正确回答所有问题?顺便说一句,真的很感激。
    • 我想这就是事情可能变得复杂的地方在您的应用程序中存储和管理。如果他们回答错了并且您想再次询问,您需要 state 来跟踪测验级别的错误答案,以及正确的标识,然后将其链接回正确的问题本身。跨度>
    • 您可以将用户对每个问题的答案存储在一个状态中,当您计算他们的分数时,创建一个仅包含不正确问题的新测验并不难。但所有这些都是相当多的工作哈哈
    猜你喜欢
    • 2016-01-11
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    相关资源
    最近更新 更多