包含嵌套对象的 setState 的最佳方法是什么

what is the best way to setState which contains nested Object

我有一个包含多个字段的表单。
为了处理我正在使用受控组件的状态。
我使用的方法如下所示。
这最初是有效的,但随着需求的变化,我不得不使用嵌套对象来定义初始状态。
handleChange 不再正常工作。
我怎样才能为嵌套对象实现相同的结果。

  const [details, setDetails] = useState({
    description: null,
    platform: "Xbox",
    region: "ASIA",
    time:{
      start: "2017-05-24T10:30",
      end: "2017-05-28T10:30",
    },
    contact: {
      email: "",
      phone: "",
      twitter: "",
      discord: "",
    }
  });

  function handleChange(evt) {
    const value = evt.target.value;
    setDetails({
      ...details,
      [evt.target.name]: value,
    });
  }

示例组件

      <TextField
        label="Description"
        onChange={handleChange}
        name="description"
        value={details.description}    
      />
         <TextField
        label="email"
        onChange={handleChange}
        name="email"
        value={details.contact.email}    
      />

contact 中的字段需要其他 handleChange

  function handleChangeContact(evt) {
    const value = evt.target.value;
    setDetails({
      ...details,
      contact: {
        ...details.contact,      
        [evt.target.name]: value,
      }
    });
  }

 <TextField
    label="email"
    onChange={handleChangeContact}
    name="email"
    value={details.contact.email}    
  />

懒惰的方式,但我会做这样的事情:

function handleNestedChange(key, event) {
  setDetails({
    ...details,
    [key]: {
      ...details[key],
      [event.target.name]: event.target.value
    }
  });
}
       <TextField
        label="email"
        onChange={(e) => handleNestedChange("contact", e)}
        name="email"
        value={details.contact.email}    
      />

您可以像这样更新嵌套对象

<TextField
        label="email"
        onChange={handleChange}
        name="contact_email"
        value={details.contact.email}    
      />

 function handleChange(evt) {
    const value = evt.target.value;
    const name = evt.target.name.split("_"); // [0: contact, 1: email]
     setDetails({ ...details, amount : { ...details[name[0]],  
    [name[1]]: value }})
  }

我认为这样效果最好。

function handleNestedChange(evt) {
  const value = evt.target.value;
  const keys = evt.target.name.split("."); 
  if(keys > 1){
    setDetails({
      ...details,
      [keys[0]]: {
        ...details[keys[0]],
        [keys[1]]: event.target.value
      }
    });
  }else{
     setDetails({
      ...details,
      [keys[0]]: event.target.value
      }
    });
  }
}
<TextField
        label="Email"
        onChange={handleChange}
        name="contact.email"
        value={details.description}    
      />

此外,如果您开始将巨大的嵌套对象存储到状态中,请查看包 immutability-helper。它使仅更新对象中的特定字段变得更容易,并且比重新创建整个对象更快。