Question: Why can't I push values in my state array in react.js?

Question

Why can't I push values in my state array in react.js?

Answers 5
Added at 2016-12-29 09:12
Tags
Question

I can add 1 item to the array it logs ["50"] in the console. But when I try to add a second value I get this error "currentScores.push is not a function". Is this the wrong way of doing it?

 class Scores extends Component {

      constructor() {
        super();
        this.addScore = this.addScore.bind(this);
        this.handleScoreChange = this.handleScoreChange.bind(this);
        this.state = {
          scores: [],
          scoreInput: '',
        };
      }

      addScore() {
        const currentScores = this.state.scores;
        const newScores = currentScores.push(this.state.scoreInput);
        this.setState({ scores: newScores });
        console.log(this.state.scores);
      }

      handleScoreChange(e) {
        this.setState({ scoreInput: e.target.value });
      }

      render() {
        const scores = this.state.scores;
        return (
                <input name="score" type="text" placeholder="Score" onChange={this.handleScoreChange}/>
                <button onClick={this.addScore(this.state.scoreInput)}>add</button>
        );
      }
    }

    export default Scores;
Answers to

Why can&#39;t I push values in my state array in react.js?

nr: #1 dodano: 2016-12-29 10:12

The problem is that push doesn't return a new array, bit the length of the amended array. So you're actually assigning state.stores to a number, which of course doesn't support push.

I can see you're trying to avoid mutating state by attempting to clone the scores array, but push will mutate it, not return a new instance. It might be better to do something like:

const newScores = [...this.state.scores, this.state.scoreInput];
this.setState({ scores: newScores });
nr: #2 dodano: 2016-12-29 10:12

Push returns the new length property of the object upon which the method was called.

You set the state of scores to the new length each time.

addScore() {
        console.log(this.state.scores);
        this.setState(state=> ({
            scores: [...state.scores, state.scoreInput]
            })
         );
      }
nr: #3 dodano: 2016-12-29 10:12

The return value of currentScores.push() is the new number of elements in the array. You then save this in your state which means that scores in your state becomes a number instead of an array.

You likely want to construct a new array instead since you are working with constant variables:

const currentScores = this.state.scores;
const newScores = currentScores.concat(this.state.scoreInput);
this.setState({ scores: newScores });
nr: #4 dodano: 2016-12-29 10:12

Two things, when you make use of push it doesn't return a new array. Make use of concat and bind the value to the addUser function.

Also wrap your elements inside a single div and write your console.log() statement to output the state value in the callback function of setState since it takes some time to mutate

 class Scores extends React.Component {

      constructor() {
        super();
        this.addScore = this.addScore.bind(this);
        this.handleScoreChange = this.handleScoreChange.bind(this);
        this.state = {
          scores: [],
          scoreInput: '',
        };
      }

      addScore() {
        const currentScores = this.state.scores;
        const newScores = currentScores.concat(this.state.scoreInput);
        this.setState({ scores: newScores }, function(){
          console.log(this.state.scores);
        });
        
      }

      handleScoreChange(e) {
        this.setState({ scoreInput: e.target.value });
      }

      render() {
        const scores = this.state.scores;
        return (
                <div>
                <input name="score" type="text" placeholder="Score" onChange={this.handleScoreChange}/>
                <button onClick={this.addScore.bind(this, this.state.scoreInput)}>add</button></div>
        );
      }
    }

    ReactDOM.render(<Scores/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

nr: #5 dodano: 2016-12-29 10:12

The problem is over here <button onClick={this.addScore(this.state.scoreInput)}> add</button>);

When you run this.addScore(this.state.scoreInput) inside the onclick, javascript runtime will call addScore function. Thats why you are getting 50~logs

Try <button onClick={ function(){this.addScore(this.state.scoreInput)}}> add</button>);

Source Show
◀ Wstecz