2

Doing a React project and keep running into a similar problem. Having trouble getting a variable into state using setState on a click. In this case i'm unable to pass my player object into state as ActivePlayer when the corresponding button gets clicked. I can however set it as a variable, but in other cases in the app I need to have it in state and this seemed like the most straightforward exampel.

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import AdminSubNav from 'components/admin-subnav';
import { getPlayers } from 'api/index.js';
import { archivePlayer } from 'api/index.js';
let players = [];
let activePlayer = {};

export default class PlayerView extends React.Component {
    constructor(props) {
    super(props);
        this.state = {
          players: [],
          activePlayer: {},
          player: {}
        }
    }

    componentWillMount() {
          getPlayers().then((response) => {
                players = response.data;
                console.log(players);
                this.setState({ players:players });
            });
    }

    onClick(player) {
        // let activePlayer = player;
        this.setState({
            activePlayer:player
        });
        console.log(activePlayer);
        console.log(this.state);
        // archivePlayer(this.props.params.id)
        //     .then(() => {
        //         this.context.router.push('/player');
        //     });
    }

    renderPlayers() {
        return players.map((player) => {
            return (
                <tr key={player.id}>
                  <td>{player.NameLast}, {player.NameFirst}</td>
                  <td>{player.teamName}</td>
                  <td><Link to='/'><i className='material-icons small'>create</i></Link></td>
                  <td><button onClick={this.onClick.bind(this, player)}><i className='material-icons small'>delete</i></button></td>
                </tr>
            );
        });
    }


  render () {

    return (
        <div>
            {/*<AdminSubNav title="Player View" route="/team/add"/>*/}
            <div className="admin-table-wrapper">
                <h3>PLAYERS</h3>
                <Link to="/player/add">ADD PLAYER</Link>
                <table className="admin-table">
                <col className="at-col1"/>
                <col className="at-col2"/>
                <col className="at-col3"/>
                <col className="at-col4"/>
                    <thead>
                         <tr>
                             <th data-field='id'>Player Name</th>
                             <th data-field='name'>Team</th>
                             <th data-field='price'>Edit</th>
                             <th data-field='price'>Archive</th>
                         </tr>
                    </thead>
                    <tbody>
                    {this.renderPlayers()}
                    </tbody>
                </table>
            </div>
        </div>
    );
  }
}
1
  • The setState documentation says this, 'setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.' Commented Feb 10, 2016 at 7:08

4 Answers 4

1

Are you sure this isn't working, or are the console.logs just not working? setState is an asynchronous function, so if you set the state and then look for it immediately after it might not be there. Try using the callback in setState like so:

this.setState({ /* state */ },() => {
   // console.log and check stuff
   // Also do any other function calls that you need to to explicitly   after the state has been updated
})

Not sure if this will solve it, but it's important to remember the async nature of setState!

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

2 Comments

Ahh yeah, that does log the state correctly. Thank you, you're the man!! that said, in another component where i am using a callback to setState, some components aren't rerendering the way i would think they would. I have an API that is called on componentWillMount and then an OnChange function that is called by a date picker that i want to recall the API with new data. Can componentWillMount only be called once? If so, do i just make the new API call directly in the handleChange function? Also, this should probaby be a new question with a code example eh? Thanks again either way!
Sweet, glad I could help! If you don't mind marking as accepted answer I'd appreciate it ;) And yea open up another question and post the link here as a comment and I'll go take a look at it!
1

try this

{this.renderPlayers.bind(this)()}

or you could also put this in the constructor

constructor(props) {
    super(props);
    this.state = {
      players: [],
      activePlayer: {},
      player: {}
    }
    this.renderPlayers = this.renderPlayers.bind(this);
}

1 Comment

One of many reasons to avoid using classes for React components.. stick to React.createClass({}) :)
0

On your renderPlayers function, you're calling

players.map((player) =>

which will refer to the top level players Array. I would try

this.state.players.map((player) =>

in your renderPlayers function

I would also try setting your state in getInitialState on your component api

getInitialState() {
  return {
          players: [],
          activePlayer: {},
          player: {}
         }
}

1 Comment

players is a global array in this guys code, works fine :(
0

Maybe the problem is in the onClick biding.

I was with the same problem and solved it biding the onClick handler, try this:

constructor(props) {
    super(props);
        this.state = {
          players: [],
          activePlayer: {},
          player: {}
        }
       this.onClick = this.onClick.bind(this);
    }

You can see it in the React docs: https://reactjs.org/docs/handling-events.html

Comments

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.