简体   繁体   中英

Why use ES6 computed property syntax for object setState?

In an example of the React docs page Forms , ES6 computed property syntax is used in a method to set the state of the name property.

handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

Based on my reading of how the computed property works, it seems like the reason it's used is so target.name can be changed -- is that so? If that's the case it seems like it would just be easier to change it there in setState rather than changing the value of the name variable.

I'm new to React and struggling to understand how the computed property syntax is applied in this example. Any help would be greatly appreciated.

Why use ES6 computed property syntax for object setState?

The computed property syntax allows you to set the key of an object dynamically .

In the case of setState , it allows you to handle different properties of the state with a single setState , and so to reuse the same event handler function on different inputs.

So instead of:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleIsGoingChange = this.handleIsGoingChange.bind(this);
    this.handleNumberOfGuestsChange = this.handleNumberOfGuestsChange.bind(this);
  }

  // a first handler, for isGoing
  handleIsGoingChange(event) {
    const target = event.target;
    const value = target.checked;

    this.setState({
      isGoing: value
    });
  }

  // a second handler, for numberOfGuests
  handleNumberOfGuestsChange(event) {
    const target = event.target;
    const value = target.value;

    this.setState({
      numberOfGuests: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleIsGoingChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleNumberOfGuestsChange} />
        </label>
      </form>
    );
  }
}

You can shorten it like this:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }


  // a single handler, for isGoing and numberOfGuests
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

When you wrap a key with array square brackets it will get the variable name as a key.

If you doesn't the key will be string. So...

let name = 'id';
let obj = { //let obj = {
  [name]:1  // id: 1
};          //};

Cause you don't want to set the "name" property, but the property which name is stored in name.

  var name = "test";

  // these are all equal:
  this.setState({ [name]: 1 })
  this.setState({ ["test"]: 1 })
  this.setState({ test: 1 })

If you don't use the computed property syntax, your function would always set the name property instead of the computed value from event.target.name , which is what you want. Your state would always look like this:

console.log(this.state);
// -> { name: 'some value' }

Maybe by writing without the ES6 syntax you will understand more what's going on.

The same code would be as below (you could run it in the snippet and see it)

One thing I would tell though is use let instead of const simply because variables created with const constantly point or bind to the same value as long as they "live". So, using const here may not let you check and/or uncheck the box, or let you increase/decrease the number.

I hope it helps you understand more.

Thanks

 class Reservation extends React.Component { constructor(props) { super(props); this.state = { isGoing: true, numberOfGuests: 2 }; this.handleInputChange = this.handleInputChange.bind(this); } handleInputChange(event) { let value; if(event.target.type==='checkbox'){ value = event.target.checked } else { value = event.target.value } this.setState({ [event.target.name]: value }); } render() { return ( <form> <label> Is going: <input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange} /> </label> <br /> <label> Number of guests: <input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange} /> </label> </form> ); } } ReactDOM.render( <Reservation />, document.getElementById('root') );
 <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM