Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS Array.push function not working in setState

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 form into the userAnswers array. It works fine for the first run of handleContinue, after that it throws an error: Uncaught TypeError: this.state.userAnswers.push is not a function(…)

import React from "react"

export default class Questions extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      questionNumber: 1,
      userAnswers: [],
      value: ''
    }

    this.handleContinue = this.handleContinue.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }

  //when Continue button is clicked
  handleContinue() {
    this.setState({
      //this push function throws error on 2nd go round
      userAnswers: this.state.userAnswers.push(this.state.value),
      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)
  }

  handleChange(event) {
    this.setState({
      value: event.target.value
    })
  }

  render() {
    const questions = [
      "Blargh?",
      "blah blah blah?",
      "how many dogs?"
    ]
    return (
      <div class="container-fluid text-center">
        <h1>{questions[this.state.questionNumber - 1]}</h1>
        <div class="radio">
          <label class="radio-inline">
            <input type="radio" class="form-control" name="trueFalse" value="true" 
            onChange={this.handleChange}/>True
          </label><br/><br/>
          <label class="radio-inline">
            <input type="radio" class="form-control" name="trueFalse" value="false" 
            onChange={this.handleChange}/>False
          </label>
          <hr/>
          <button type="button" class="btn btn-primary" 
          onClick={this.handleContinue}>Continue</button>
        </div>
      </div>
    )
  }
}
like image 854
Jackson Lenhart Avatar asked Dec 09 '16 03:12

Jackson Lenhart


People also ask

Why push is not working in React JS?

The "push is not a function" error occurs when the push() method is called on a value that is not an array. To solve the error, convert the value to an array before calling the method, or make sure to only call the push() method on valid arrays.

How do you push to an array in state React?

Use the spread syntax to push an element into a state array in React, e.g. setNames(current => [... current, 'Carl']) . The spread syntax (...) will unpack the existing elements of the state array into a new array where we can add other elements.

How do you update an array of objects in setState React?

To update an object in an array in React state: Use the map() method to iterate over the array. On each iteration, check if a certain condition is met. Update the object that satisfies the condition and return all other objects as is.

Why is Forstate not updating?

It is the failure of the re-render to reflect the updated value of the state. The “useState” set method is asynchronous; hence, the updates are not reflected immediately.


2 Answers

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
}
like image 108
p4sh4 Avatar answered Sep 22 '22 13:09

p4sh4


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

like image 23
duwalanise Avatar answered Sep 22 '22 13:09

duwalanise