如何将类组件转换为功能组件

时间:2020-07-26 09:50:43

标签: javascript reactjs functional-programming mern

我仅在类组件上工作,但现在我正在尝试功能组件。但是我对功能组件了解不多。 但是将类转换为函数后,我的代码无法正常工作

错误:(在我的功能组件代码中)如果我单击“下一步”按钮,则它不会显示第二个问题,但是再次单击后,它将显示第二个问题。 然后我点击返回按钮,然后显示下一个问题而不是上一个问题

但是我的Class组件代码工作正常。但是在功能组件中进行转换后,它无法正常工作。表示我转换的功能组件代码不正确。

请帮助我将类组件转换为功能组件。或者告诉我转换后的功能组件代码中有什么不正确。

... ...

原始类组件

import React, { Fragment, Component } from "react";

import classnames from "classnames";
import isEmpty from "../is-empty";
import questionsArray from "../questions.json";

export default class PlayQuiz extends Component {
  constructor(props) {
    super(props);
    this.state = {
      questions: questionsArray,
      currentQuestion: {},
      nextQuestion: {},
      previousQuestion: {},
      answer: "",
      numberOfQuestions: 0,
      numberOfAnsweredQuestions: 0,
      currentQuestionIndex: 0,
      score: 0,
      correctAnswers: 0,
      wrongAnswers: 0,
      nextButtonDisabled: false,
      previousButtonDisabled: true,
    };
  }

  componentDidMount() {
    const {
      questions,
      currentQuestion,
      nextQuestion,
      previousQuestion,
    } = this.state;
    this.displayQuestions(
      questions,
      currentQuestion,
      nextQuestion,
      previousQuestion
    );
  }

  displayQuestions = (
    questions = this.state.questions,
    currentQuestion,
    nextQuestion,
    previousQuestion
  ) => {
    let { currentQuestionIndex } = this.state;
    if (!isEmpty(this.state.questions)) {
      questions = this.state.questions;
      currentQuestion = questions[currentQuestionIndex];
      nextQuestion = questions[currentQuestionIndex + 1];
      previousQuestion = questions[currentQuestionIndex - 1];
      const answer = currentQuestion.answer;
      this.setState(
        {
          currentQuestion: currentQuestion,
          nextQuestion,
          previousQuestion,
          numberOfQuestions: questions.length,
          answer,
        },
        () => {
          this.showOptions();
          this.handleDisableButton();
        }
      );
    }
  };

  handleOptionClick = (e) => {
    e.preventDefault();
    if (e.target.innerHTML.toLowerCase() === this.state.answer.toLowerCase()) {
      console.log("correct");
      this.correctAnswer();
    } else {
      console.log("incorrect");
      this.wrongAnswer();
    }
  };

  correctAnswer = () => {
    this.setState(
      (prevState) => ({
        score: prevState.score + 1,
        correctAnswers: prevState.correctAnswers + 1,
        currentQuestionIndex: prevState.currentQuestionIndex + 1,
        numberOfAnsweredQuestions: prevState.numberOfAnsweredQuestions + 1,
      }),
      () => {
        if (this.state.nextQuestion === undefined) {
          this.endGame();
        } else {
          this.displayQuestions(
            this.state.questions,
            this.state.currentQuestion,
            this.state.nextQuestion,
            this.state.previousQuestion
          );
        }
      }
    );
  };

  wrongAnswer = () => {
    this.setState(
      (prevState) => ({
        wrongAnswers: prevState.wrongAnswer + 1,
        currentQuestionIndex: prevState.currentQuestionIndex + 1,
        numberOfAnsweredQuestions: prevState.numberOfAnsweredQuestions + 1,
      }),
      () => {
        if (this.state.nextQuestion === undefined) {
          this.endGame();
        } else {
          this.displayQuestions(
            this.state.questions,
            this.state.currentQuestion,
            this.state.nextQuestion,
            this.state.previousQuestion
          );
        }
      }
    );
  };

  showOptions = () => {
    const options = Array.from(document.querySelectorAll(".option"));

    options.forEach((option) => {
      option.style.visibility = "visible";
    });
  };

  handleNextButtonClick = () => {
    if (this.state.nextQuestion !== undefined) {
      this.setState(
        (prevState) => ({
          currentQuestionIndex: prevState.currentQuestionIndex + 1,
        }),
        () => {
          this.displayQuestions(
            this.state.question,
            this.state.currentQuestion,
            this.state.nextQuestion,
            this.state.previousQuestion
          );
        }
      );
    }
  };

  handlePreviousButtonClick = () => {
    if (this.state.previousQuestion !== undefined) {
      this.setState(
        (prevState) => ({
          currentQuestionIndex: prevState.currentQuestionIndex - 1,
        }),
        () => {
          this.displayQuestions(
            this.state.question,
            this.state.currentQuestion,
            this.state.nextQuestion,
            this.state.previousQuestion
          );
        }
      );
    }
  };

  handleQuitButtonClick = () => {
    if (window.confirm("Are you sure want to quite Quiz")) {
      //  this.props.history.push("/");
    }
  };
  handleButtonClick = (e) => {
    e.preventDefault();

    switch (e.target.id) {
      case "next-button":
        this.handleNextButtonClick(e);
        break;

      case "previous-button":
        this.handlePreviousButtonClick(e);
        break;

      case "quit-button":
        this.handleQuitButtonClick(e);
        break;

      default:
        break;
    }
  };

  handleDisableButton = () => {
    if (
      this.state.previousQuestion === undefined ||
      this.state.currentQuestionIndex === 0
    ) {
      this.setState({
        previousButtonDisabled: true,
      });
    } else {
      this.setState({
        previousButtonDisabled: false,
      });
    }

    if (
      this.state.nextQuestion === undefined ||
      this.state.currentQuestionIndex + 1 === this.state.numberOfQuestions
    ) {
      this.setState({
        nextButtonDisabled: true,
      });
    } else {
      this.setState({
        nextButtonDisabled: false,
      });
    }
  };
  endGame = () => {
    alert("Game has ended.");
    const { state } = this;
    const playerStats = {
      score: state.score,
      numberOfQuestions: state.numberOfQuestions,
      numberOfAnsweredQuestions: state.correctAnswers + state.wrongAnswers,
      correctAnswers: state.correctAnswers,
      wrongAnswers: state.wrongAnswers,
    };
    console.log(playerStats);
    setTimeout(() => {
      this.props.history.push("/play/QuizSummary", playerStats);
    }, 1000);
  };

  render() {
    const {
      currentQuestion,
      currentQuestionIndex,
      numberOfQuestions,
    } = this.state;
    return (
      <Fragment>
        <div className="questions">
          <h2>Quiz Mode</h2>
          <br />
          <h5>
            {currentQuestionIndex + 1}.{currentQuestion.question}
          </h5>
          <div className="options-container">
            <p onClick={this.handleOptionClick} className="option">
              {currentQuestion.opt1}
            </p>
            <p onClick={this.handleOptionClick} className="option">
              {currentQuestion.opt2}
            </p>
          </div>
          <div className="options-container">
            <p onClick={this.handleOptionClick} className="option">
              {currentQuestion.opt3}
            </p>
            <p onClick={this.handleOptionClick} className="option">
              {currentQuestion.opt4}
            </p>
          </div>
          <div className="button-container">
            <button
              className={classnames("", {
                disabled: this.state.nextButtonDisabled,
              })}
              id="previous-button"
              onClick={this.handleButtonClick}
            >
              Previous
            </button>
            <button
              className={classnames("", {
                disabled: this.state.nextButtonDisabled,
              })}
              id="next-button"
              onClick={this.handleButtonClick}
            >
              Next
            </button>
            <button id="quit-button" onClick={this.handleButtonClick}>
              Quit
            </button>
          </div>
        </div>
      </Fragment>
    );
  }
}

我的转换功能组件

import React, { Fragment, useEffect, useState } from "react";
import { withRouter } from "react-router-dom";

import classnames from "classnames";
import isEmpty from "../is-empty";
import questionsArray from "../questions.json";

const PlayQuiz = ({withRouter}) => {
  const [questions, setQuestions] = useState(questionsArray);
  const [currentQuestion, setCurrentQuestion] = useState({
    content: "",
    question: "",
    opt1: "",
    opt2: "",
    opt3: "",
    opt4: "",
    answer: "",
  });
  const [nextQuestion, setNextQuestion] = useState({
    content: "",
    question: "",
    opt1: "",
    opt2: "",
    opt3: "",
    opt4: "",
    answer: "",
  });
  const [previousQuestion, setPreviousQuestion] = useState({
    content: "",
    question: "",
    opt1: "",
    opt2: "",
    opt3: "",
    opt4: "",
    answer: "",
  });
  const [numberOfQuestions, setNumberOfQuestions] = useState(0);
  const [numberOfAnsweredQuestions, setNumberOfAnsweredQuestions] = useState(0);
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  const [score, setScore] = useState(0);
  const [correctAnswers, setCorrectAnswers] = useState(0);
  const [wrongAnswers, setWrongAnswers] = useState(0);
  const [nextButtonDisabled, toggleNextButtonDisabled] = useState(false);
  const [previousButtonDisabled, togglePreviousButtonDisabled] = useState(true);

  useEffect(() => {
    console.log("useEffect");
    displayQuestion(questions, currentQuestion, nextQuestion, previousQuestion);
  }, []);

  const displayQuestion = (
    questions,
    currentQuestion,
    nextQuestion,
    previousQuestion
  ) => {
    if (!isEmpty(questions)) {
      // questions = questions;
      console.log("current Question Index:" + currentQuestionIndex);
      console.log("display");
      currentQuestion = questions[currentQuestionIndex];
      nextQuestion = questions[currentQuestionIndex + 1];
      previousQuestion = questions[currentQuestionIndex - 1];
      setCurrentQuestion(currentQuestion);
      setNextQuestion(nextQuestion);
      setPreviousQuestion(previousQuestion);
      setNumberOfQuestions(questions.length);
      // showOption();
      handleDisableButton();
    }
  };

  const handleOptionClick = (e) => {
    e.preventDefault();
    if (
      e.target.innerHTML.toLowerCase() === currentQuestion.answer.toLowerCase()
    ) {
      console.log("correct");
      correctAnswer();
    } else {
      console.log("incorrect");
      wrongAnswer();
    }
  };

  const correctAnswer = () => {
    setScore(score + 1);
    setCorrectAnswers(correctAnswers + 1);
    setCurrentQuestionIndex(currentQuestionIndex + 1);
    setNumberOfAnsweredQuestions(numberOfAnsweredQuestions + 1);

    if (nextQuestion === undefined) {
      endQuiz();
    } else {
      displayQuestion(
        questions,
        currentQuestion,
        nextQuestion,
        previousQuestion
      );
    }
  };

  const wrongAnswer = () => {
    setWrongAnswers(wrongAnswers + 1);
    setCurrentQuestionIndex(currentQuestionIndex + 1);
    setNumberOfAnsweredQuestions(numberOfAnsweredQuestions + 1);

    if (nextQuestion === undefined) {
      endQuiz();
    } else {
      displayQuestion(
        questions,
        currentQuestion,
        nextQuestion,
        previousQuestion
      );
    }
  };

  const handleNextButtonClick = (e) => {
    e.preventDefault();

    if (nextQuestion !== undefined) {
      setCurrentQuestionIndex(currentQuestionIndex + 1);
      displayQuestion(
        questions,
        currentQuestion,
        nextQuestion,
        previousQuestion
      );
    }
  };

  const handlePreviousButtonClick = (e) => {
    e.preventDefault();

    if (previousQuestion !== undefined) {
      setCurrentQuestionIndex(currentQuestionIndex - 1);
      displayQuestion(
        questions,
        currentQuestion,
        nextQuestion,
        previousQuestion
      );
    }
  };

 
  const handleQuitButtonClick = () => {
    if (window.confirm("Are you sure want to quite Quiz")) {
      //  this.props.history.push("/");
    }
  };
  const handleButtonClick = (e) => {
    e.preventDefault();

    switch (e.target.id) {
      case "next-button":
        handleNextButtonClick(e);
        break;

      case "previous-button":
        handlePreviousButtonClick(e);
        break;

      case "quit-button":
        handleQuitButtonClick(e);
        break;

      default:
        break;
    }
  };

  const handleDisableButton = () => {
    if (previousQuestion === undefined || currentQuestionIndex === 0) {
      togglePreviousButtonDisabled(true);
    } else {
      togglePreviousButtonDisabled(false);
    }

    if (
      nextQuestion === undefined ||
      currentQuestionIndex + 1 === numberOfQuestions
    ) {
      toggleNextButtonDisabled(true);
    } else {
      toggleNextButtonDisabled(false);
    }
  };
  const endQuiz = () => {
    alert("Quiz has ended.");
    const playerStats = {
      score: score,
      numberOfQuestions: numberOfQuestions,
      numberOfAnsweredQuestions: numberOfAnsweredQuestions,
      correctAnswers: correctAnswers,
      wrongAnswers: wrongAnswers,
    };
    console.log(playerStats);
    console.log(questionsData.questions);
    console.log(questionsArray);

    history.push("/give-exam/QuizSummary", playerStats);
  };

  return (
    <Fragment>
      <div className="questions">
        <h2>Quiz Mode</h2>
        <br />
        <h5>
          {currentQuestionIndex + 1}.{currentQuestion.question}
        </h5>
        <div className="options-container">
          <p onClick={(e) => handleOptionClick(e)} className="option">
            {currentQuestion.opt1}
          </p>
          <p onClick={(e) => handleOptionClick(e)} className="option">
            {currentQuestion.opt2}
          </p>
        </div>
        <div className="options-container">
          <p onClick={(e) => handleOptionClick(e)} className="option">
            {currentQuestion.opt3}
          </p>
          <p onClick={(e) => handleOptionClick(e)} className="option">
            {currentQuestion.opt4}
          </p>
        </div>
        <div className="button-container">
          <button
            className={classnames("", { disabled: previousButtonDisabled })}
            id="previous-button"
            onClick={(e) => handleButtonClick(e)}
          >
            Previous
          </button>
          <button
            className={classnames("", { disabled: nextButtonDisabled })}
            id="next-button"
            onClick={(e) => handleButtonClick(e)}
          >
            Next
          </button>
          <button id="quit-button" onClick={(e) => handleButtonClick(e)}>
            Quit
          </button>
        </div>
      </div>
    </Fragment>
  );
};


export default withRouter(PlayQuiz);

questionArray.json

[
  {
    "question": "What temperature does water boil at?",
    "opt1": "50 degrees Celcius",
    "opt2": "25 degrees Celcius",
    "opt3": "100 degrees Celcius",
    "opt4": "150 degrees Celcius",
    "answer": "100 degrees Celcius"
  },

  {
    "question": "Who wrote Julius Caesar, Macbeth and Hamlet?",
    "opt1": "Wole Soyinka",
    "opt2": "William Shakespeare",
    "opt3": "Ngozi Chimamanda Adichie",
    "opt4": "Dan Brown",
    "answer": "William Shakespeare"
  },

  {
    "question": "What did the crocodile swallow in Peter Pan?",
    "opt1": "A Book",
    "opt2": "A Computer",
    "opt3": "A pair of shoes",
    "opt4": "Alarm Clock",
    "answer": "Alarm Clock"
  },

  {
    "question": "Which is the only mammal that can’t jump?",
    "opt1": "Dog",
    "opt2": "Elephant",
    "opt3": "Goat",
    "opt4": "Lion",
    "answer": "Elephant"
  },

  {
    "question": "Who lived at 221B, Baker Street, London?",
    "opt1": "Tony Stark",
    "opt2": "Morgan Freeman",
    "opt3": "Sherlock Holmes",
    "opt4": "Samuel L. Jackson",
    "answer": "Sherlock Holmes"
  },
]

isEmpty.js

const isEmpty = (value) =>
  value === undefined ||
  value === null ||
  (typeof value === "object" && Object.keys(value).length === 0) ||
  (typeof value === "string" && value.trim().length === 0);

export default isEmpty;

1 个答案:

答案 0 :(得分:0)

您可以将类组件包装在高阶组件中,然后将其变成功能组件。

import React from 'react';
import { useHook } from '../hooks/useHook';

export const withFunctionalComponent = (Component) => {
  return (props) => {
    const hookValue = useHook();

    return <Component value={hookValue} {...props} />;
  };
};

并像这样使用它:

import React from 'react';
import { withFunctionalComponent } from './withFunctionalComponent';

class ClassComponent extends React.Component {
  render() {
    return <div>Hello, {this.props.value}</div>;
  }
}

export default withFunctionalComponent (ClassComponent)