Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Child Calling Parent Method Can't Access State

I have 3 components that are nested App->GameList->GameItem

I have a method on the App(parent) component that gets call via the onClick event in the GameItem(child) component

When the GameItem component is clicked it fires the App component method to access the state in the App component.

However when I try to access the state this.state.gamesVM I get a

Uncaught TypeError: Cannot read property 'gamesVM' of null

.

APP COMPONENT

export default class App extends React.Component {

  state = {
    userId: 3,
    gamesVM: [],
  }

  componentDidMount() {
    const pGames = getGames();
    const pPicks = getPicks();
    const pTeams = getTeams();

    Promise.all([pGames, pPicks, pTeams])
      .then(payload => {
        const gamesVM = this.getGamesVM(payload);
        this.setState({gamesVM});
      });
  }

  getGamesVM(payload) {
    // ... code to get and map gamesVM
  }

  teamPicked(team, away, home) { // gets called from child component
    console.log(this.state.gamesVM); // Uncaught TypeError: Cannot read property 'gamesVM' of null
    console.log(this.state.userId); // Uncaught TypeError: Cannot read property 'userId' of null
    // ...
    console.log(this.state.anything); // Uncaught TypeError: Cannot read property 'anything' of null
  }

  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit}>
          <GameList
            gamesVM={this.state.gamesVM}
            teamPicked={this.teamPicked}
          />
          <input type="submit" value="Save" />
        </form>
      </div>
    );
  }
}

.

GAMELIST COMPONENT

export default class GameList extends React.Component {
  render() {
    return (
      <div className='matchups'>
        {this.props.gamesVM.map(game =>
          <GameItem
            teamPicked={this.props.teamPicked}
            key={game.id}
            {...game}
          />
        )}
      </div>
    )
  }
}

.

GAMEITEM COMPONENT

export default class GameItem extends React.Component {

  render() {

    let awayPickCheckbox = null;

    if (!this.props.isGameStarted) {

      awayPickCheckbox = <li>
            <input type="checkbox" id={this.props.id + this.props.awayTeam} />
            <label
              htmlFor={this.props.id + this.props.awayTeam}
              onClick={this.props.teamPicked.bind(this, 'away', this.props.id + this.props.awayTeam, this.props.id + this.props.homeTeam)}
            >
              {this.props.awayTeam}
            </label>
          </li>;

    } else {

      awayPickCheckbox = <li>
            <label>{this.props.awayTeam}</label>
          </li>
    }


    return (
      <div className="single-matchup">
        <ul className="away-team clearfix">
          {awayPickCheckbox}
        </ul>
      </div>
    )
  }
}
like image 551
locnguyen Avatar asked Jan 21 '26 01:01

locnguyen


1 Answers

You need t0 bind method with this.If you forget to bind this.teamPicked and pass, this will be undefined when the function is actually called.

Inside constructor functin,

this.teamPicked = this.teamPicked.bind(this)


 teamPicked(team, away, home) { // gets called from child component
    console.log(this.state.gamesVM); // Uncaught TypeError: Cannot read property 'gamesVM' of null
    console.log(this.state.userId); // Uncaught TypeError: Cannot read property 'userId' of null
    // ...
    console.log(this.state.anything); // Uncaught TypeError: Cannot read property 'anything' of null
  }

OR,

  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit}>
          <GameList
            gamesVM={this.state.gamesVM}
            teamPicked={this.teamPicked.bind(this)}
          />
          <input type="submit" value="Save" />
        </form>
      </div>
    );
  }
}
like image 149
Ved Avatar answered Jan 22 '26 16:01

Ved