1

I bet this has something to do with asynchronicity.

Basically, I am checking if a string (an answer to a question) already exists, and if so, the page should just display a message, otherwise should add the new question to an array.

So in order to refactor the code, I have created a function called isDuplicateAnswer (yes, it's bound to the component). Here is the code for it:

 isDuplicateAnswer() {
    if (this.state.answersToCurrentQuestion.length > 0) {
      this.state.answersToCurrentQuestion.map(answer => {
        if (this.state.answerTextTyped === answer.text) {
          console.log("true"); // executed twice but then adds it to the array (not supposed to)
          return true;
        }
      });
    }
  }

Based on this check the code will do the following:

if (
      event.target.id === "submitAnswer" &&
      this.state.answerTextTyped !== null &&
      this.isDuplicateAnswer()
    ) {
      console.log("Something is wrong"); // This line is never executed (no log, no message)
      return this.props.handleMessage(
        "There is already another answer with this text. Please add a different one."
      );
    } else if (
      event.target.id === "submitAnswer" &&
      this.state.answerTextTyped !== null &&
      !this.isDuplicateAnswer()
    ) {
      console.log("Everything OK"); // not displayed but rest of the code goes through (answer added)
      this.setState({ answerText: this.state.answerTextTyped }, () => {
        (() => {
          let answersToCurrentQuestion = [
            ...this.state.answersToCurrentQuestion,
          ];
          answersToCurrentQuestion.push({
            text: this.state.answerText,
            isCorrect: this.state.isCorrectAnswer,
          });
          this.setState({ answersToCurrentQuestion });
          if (this.state.isCorrectAnswer === true) {
            this.incrementCorrectAnswers();
          }
        })();
        (() => {
          this.props.handleMessage("");
          this.setState({
            isValid: true,
            isCorrectAnswer: false,
            answerTextTyped: null,
          });
          this.refreshAnswerTypedForm();
          this.getAnswerTypedForm();
        })();
      });
    }

My problem is that if isDuplicateAnswer is false, as my log says "Everything is Ok", but when it returns true, the answer is created, resulting in an error due to the HTML key being not unique, even though the log from isDuplicateAnswer is displayed twice.

Given that the other two checks in the guard are working correctly, what am I doing wrong here?

EDIT

this is the state right before clicking on "Add Answer", which id is submitAnswer

enter image description here

1 Answer 1

3

There are multiple things wrong in your code. I will list the ones that are most obvious to me:

1) Your isDuplicateAnswer() method will always return undefined which under if condition will always evaluate to false. That is why Something is wrong is never executed - it will never go to that block.

2) This one is linked to 1) above. Basically map doesn't return a boolean, moreover you have to return the result of the function which you're not doing as well. To fix this, use a method like some which does return a boolean:

isDuplicateAnswer() {
       return this.state.answersToCurrentQuestion.some(answer => this.state.answerTextTyped === answer.text);
        // If we find that answer already exists, some will return true, otherwise false.
  }

3) In the 2nd block, do not check for event.target.id === "submitAnswer" && this.state.answerTextTyped !== null twice. Just do:

if (event.target.id === "submitAnswer" && this.state.answerTextTyped !== null) {
    if (isDuplicateAnswer()) {
        console.log("Something is wrong");
        return this.props.handleMessage("There is already another answer with this text. Please add a different one.");
        // No setState call to change anything.
    } else {
        // Call setState and add your answer.
    }

Sign up to request clarification or add additional context in comments.

3 Comments

some is a more straightfoward alternative to find that returns an actual boolean (both should work though). Also, the length check is redundant. The whole function could just be return this.state.answersToCurrentQuestion.some(answer => this.state.answerTextTyped === answer.text)
Yes Jacob, almost forgot about some. Updating :)
Thank guys, I probably would have never made it...I am new to JS

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.