Home > front end >  onChange function for updating state with nested objects on form
onChange function for updating state with nested objects on form

Time:03-16

I've got an form with different inputs that populates the next state defined like

const [userTaxData, setUserTaxData] = React.useState({
        businessName: "",
        rfc: "",
        address: {
            street: "",
            number: 0,
            suburb: "",
            city: "",
            state: "",
            country: "",
            zcode: 0
        }
    }); 

and the handleChange function defined like

const handleChange = (e) => {
        setUserTaxData({
            ...userTaxData,
            [e.target.name]: e.target.value
        });
    };

But the problema I've faced is that when I try to change the "zcode" property it is not working and it is because is inside the "address" object, so I need you support because I don't know how to access to "address" properties.

CodePudding user response:

I think zcode is a widow object or proto a method on the proto widow object

businessName.address.zcode

CodePudding user response:

You can't update nested object states with string keys, however if you flatten the object, you can.

Example:

const flattenObject = (obj) => Object.assign({}, ... function _flatten(o) {
  return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({
    [k]: o[k]
  })))
}(obj))

const unflattenObject = (obj) => {
  var result = {}
  for (var i in data) {
    var keys = i.split('.')
    keys.reduce(function(r, e, j) {
      return r[e] || (r[e] = isNaN(Number(keys[j   1])) ? (keys.length - 1 == j ? data[i] : {}) : [])
    }, result)
  }
  return result
}

const handleChange = (e) => {
  const flattened = flattenObject(userTaxData)

  flattened[e.target.name] = e.target.value

  const unflattened = unflattenObject(flattened)

  setUserTaxData(unflattened);
};

(Flattening code taken from this SO post, unflattening code taken from this SO post)

CodePudding user response:

A simple way to do it is to test if you have update inside address property or not :

const handleChange = (e) => {
  
    if (Object.keys(userTaxData.address).includes(e.target.name)) {
      setUserTaxData({
        ...userTaxData,
        address: { ...userTaxData.address, [e.target.name]: e.target.value },
      });
    } else {
      setUserTaxData({
        ...userTaxData,
        [e.target.name]: e.target.value,
      });
    }
  };
  • Related