Andrew
Andrew

Reputation: 149

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>
    );
  }
}

Upvotes: 1

Views: 1691

Answers (5)

Ghias Ali
Ghias Ali

Reputation: 327

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}})
    }
    }

Upvotes: 0

Mark Kovalenko
Mark Kovalenko

Reputation: 151

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: ''
}

Upvotes: 0

Vedant
Vedant

Reputation: 203

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
        }
    })
}

Upvotes: 1

stever
stever

Reputation: 1241

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;

Upvotes: 0

Cuong Vu
Cuong Vu

Reputation: 3733

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.

Upvotes: 0

Related Questions