简体   繁体   中英

React update state with nested object

I have a form, and when I submit it i want to update the state. Right now only name and surname works. How with the function handleChange can I also update the address, which is nested object? Or do I need to write another function for this? Thanks for help

class Form extends Component {
  constructor(props){
    super(props);

    this.state = {
        name: '',
        surname: '',
        address: {
            street: '',
            city: '',
        },
    }
  }

  handleChange = e => {
    this.setState({ 
      [e.target.name]: e.target.value,   
    })
  }

  handleSubmit = e => {
    e.preventDefault();
  }

  render() {
    const {name, surname} = this.state;
    const { street, city} = this.state.address;

    return (
      <form onSubmit={this.handleSubmit}>
        <input type='text'
          value={name} 
          name='name'
          onChange={this.handleChange} />
        <input type='text'
          value={surname} 
          name='surname'
          onChange={this.handleChange} />
        <input type='text'
          value={street}
          name='street' 
          onChange={this.handleChange} />
        <input type='text'
          value={city} 
          name='city'
          onChange={this.handleChange} />
        <input type='submit' value='Submit' />
      </form>
    );
  }
}

You must have name attribute in your form elements, and then check for that name value to setState . So the render() method look like this

render() {
  const {name, surname} = this.state;
  const { street, city} = this.state.address;

  return (
    <form onSubmit={this.handleSubmit}>
      <input type='text'
        name={name}
        value={name}
        onChange={this.handleChange} />
      <input type='text'
        name={surname}
        value={surname}
        onChange={this.handleChange} />
      <input type='text'
        name={street}
        value={street}
        onChange={this.handleChange} />
      <input type='text'
        name={city}
        value={city}
        onChange={this.handleChange} />
      <input type='submit' value='Submit' />
    </form>
  );
}

and handleChange()

handleChange = e => {
  const name = e.target.name;
  if (name === 'city' || name === 'street') {
    this.setState({
      address: {
        ...state.address,
        [name]: e.target.value
      }
    });
  } else {
    this.setState({
      [name]: e.target.value
    });
  }
};

the ... is ES6 Spread Operator , It's the cleanest way to update nested state in React.

You just need access to street and city? Just destructure the address first like this.

Change

const {name, surname} = this.state;
const { street, city} = this.state.address;

to

const {name, surname, address } = this.state;
const { street, city} = address;

I would recommend you to write separate change handler for address . It will keep your code simple and easy to understand instead of adding unnecessary complexity to this simple method.

function handleAddressChange = e => {
    const {name, value} = event.target
    this.setState(({ address }) => {
        address: {
            ...address,
            [name]: value
        }
    })
}

I know that all of you have faced a similar task, but the whole point is to remake the original state. React is not focused on working with nested states.

this.state = {
    name: '',
    surname: '',
    street: '',
    city: ''
}

In case if the name is changed or further fields added in state, then we can use below structure.

  const onChange = (e) => {
       const{name, value} = e.target;
       const {address} = {...this.state}
       if(this.state.hasOwnProperty(name)){
        // if it is true, it means outside property
          this.setState({...this.sate,[name]:value})
       }
       else if(address.hasOwnProperty(name)){
      // if true,It means inner field object i-e address
          this.setState({...this.state,address:{...address,[name]:value}})
    }
    }

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