0

I am attempting to update an object of names in the state before passing it as a props to another component.

// some code above

this.state = {
    // some other states
    playerName: {
        player1Name: 'Default Player 1 Name',
        player2Name: 'Default Player 2 Name',
        player3Name: 'Default Player 3 Name'
    }
};
this.nameChange = this.nameChange.bind(this);

nameChange(e){
    this.setState( prevState => ({
        playerName: {
            ...prevState.playerName,
            [e.target.id]: e.target.value
        }
    })
}

render(){
    return(
        <div>
            <input type='name' id='player1Name' onChange={this.nameChange}/>
            <input type='name' id='player2Name' onChange={this.nameChange}/>
            <input type='name' id='player3Name' onChange={this.nameChange}/>
        </div>
    )
}

However, it returns the error of unable to read 'id' of null and 'value' of null

MongChangHsi
  • 103
  • 1
  • 12

2 Answers2

0

you need use name in input and e.target.name in handler. Please check this example:

import React from "react";

export default class PlayerName extends React.Component {
    state = {
        // some other states
        playerName: {
            player1Name: 'Default Player 1 Name',
            player2Name: 'Default Player 2 Name',
            player3Name: 'Default Player 3 Name'
        }
    };

    nameChange = (e) => {
        const name = e.target.name;
        const value = e.target.value;

         this.setState(prevState => ({
            playerName: {
                ...prevState.playerName,
                [name]: value
            }
        }));
        console.log( this.state);
    };

    render() {
        return (
            <div>
                <input type='name' name='player1Name' onChange={this.nameChange}/>
                <input type='name' name='player2Name' onChange={this.nameChange}/>
                <input type='name' name='player3Name' onChange={this.nameChange}/>
            </div>
        )
    }
}
Khabir
  • 5,370
  • 1
  • 21
  • 33
0

State updates are asynchronous, and react uses synthetic events, so by the time the queued state update is processed the event has been nullified and returned back to the pool. You can either destructure the id and value properties before enqueueing the update.

nameChange(e){
  const { id, value } = e.target;
  this.setState( prevState => ({
    playerName: { ...prevState.playerName, [id]: value }
  });
}

Or you can flag the event to persist (event pooling)

Note:

If you want to access the event properties in an asynchronous way, you should call event.persist() on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.

nameChange(e){
  e.persist();
  this.setState( prevState => ({
    playerName: { ...prevState.playerName, [e.target.id]: e.target.value }
  })
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Thanks! Never knew about this as many tutorials I went through always used this.setState({ [e.target.id]: e.target.value)}. Hence I thought it can be reused it this way when it comes to updating a list. Will read more about Synthetic events! – MongChangHsi May 30 '20 at 03:07