ReactJS Array.push function not working in setState

前端 未结 5 1306
粉色の甜心
粉色の甜心 2021-01-17 22:18

I\'m making a primitive quiz app with 3 questions so far, all true or false. In my handleContinue method there is a call to push the users input from a radio fo

相关标签:
5条回答
  • 2021-01-17 22:41

    Do not modify state directly! In general, try to avoid mutation.

    Array.prototype.push() mutates the array in-place. So essentially, when you push to an array inside setState, you mutate the original state by using push. And since push returns the new array length instead of the actual array, you're setting this.state.userAnswers to a numerical value, and this is why you're getting Uncaught TypeError: this.state.userAnswers.push is not a function(…) on the second run, because you can't push to a number.

    You need to use Array.prototype.concat() instead. It doesn't mutate the original array, and returns a new array with the new concatenated elements. This is what you want to do inside setState. Your code should look something like this:

    this.setState({
      userAnswers: this.state.userAnswers.concat(this.state.value),
      questionNumber: this.state.questionNumber + 1
    }
    
    0 讨论(0)
  • 2021-01-17 22:43

    Array.push does not returns the new array. try using

    this.state.userAnswers.concat([this.state.value])
    

    this will return new userAnswers array

    References: array push and array concat

    0 讨论(0)
  • 2021-01-17 22:47

    You should treat the state object as immutable, however you need to re-create the array so its pointing to a new object, set the new item, then reset the state.

     handleContinue() {
        var newState = this.state.userAnswers.slice();
        newState.push(this.state.value);
    
        this.setState({
          //this push function throws error on 2nd go round
          userAnswers: newState,
          questionNumber: this.state.questionNumber + 1
        //callback function for synchronicity
        }, () => {
          if (this.state.questionNumber > 3) {
            this.props.changeHeader(this.state.userAnswers.toString())
            this.props.unMount()
          } else {
            this.props.changeHeader("Question " + this.state.questionNumber)
          }
        })
        console.log(this.state.userAnswers)
      }
    

    Another alternative to the above solution is to use .concat(), since its returns a new array itself. Its equivalent to creating a new variable but is a much shorter code.

    this.setState({
      userAnswers: this.state.userAnswers.concat(this.state.value),
      questionNumber: this.state.questionNumber + 1
    }
    
    0 讨论(0)
  • 2021-01-17 22:53

    The recommended approach in later React versions is to use an updater function when modifying states to prevent race conditions:

    this.setState(prevState => ({
      userAnswers: [...prevState.userAnswers, this.state.value] 
    }));
    
    0 讨论(0)
  • 2021-01-17 22:59

    I have found a solution. This shoud work for splice and others too. Lets say that I have a state which is an array of cars:

    this.state = {
      cars: ['BMW','AUDI','mercedes']
    };
    this.addState = this.addState.bind(this);
    

    Now, addState is the methnod that i will use to add new items to my array. This should look like this:

      addState(){
    
    let arr = this.state.cars;
    arr.push('skoda');
    this.setState({cars: arr});
    }
    

    I have found this solution thanks to duwalanise. All I had to do was to return the new array in order to push new items. I was facing this kind of issue for a lot of time. I will try more functions to see if it really works for all functions that normally won't. If anyone have a better idea how to achieve this with a cleaner code, please feel free to reply to my post.

    0 讨论(0)
提交回复
热议问题