React js useState 钩子。单击复选框时如何更新其中包含数组的 json 对象的状态

And*_*son 5 javascript json handlebars.js reactjs react-hooks

stringified通过 lamda 服务器将我的状态作为变量从表单发送到 POST 请求,然后解析它并将其发送到 sendgrid,我在那里使用发送网格模板功能。这要求我将 json 格式化为这样,以便循环遍历一个特定部分(多个复选框),所有部分都应该具有相同的键但不同的值,由reason="Weight Loss"表单中的 a 设置。以下是最终 json 的形成方式。

{
  "name" :"anders",
  "message" : "winfsdafasfdsfsadfsadnipeg",
  "package" : "silver",
  "email" : "email@email.com",
  "subject" : "fdsafas",
  "data":{
      "reasonArray":[
         {
            "reason":"weightLoss"
         },
         {
            "reason":"Sport"
         }
      ]
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以做一些魔术并循环检查复选框中选中的原因

<ol>
  {{#each data.reasonArray}}
    <li>{{this.reason}} </li>
  {{/each}}
</ol>
Run Code Online (Sandbox Code Playgroud)

现在,如果我使用单个键值对离开状态并且没有该data部分,我就可以使用它了。这是我最初的工作状态。

const [formState, setFormState] = React.useState({
    name: "",
    package: `${data.datoCmsPricing.title}`,
    email: "",
    subject: "",
    weightLoss:"",
    strength:"",
    sport:"",
    message: "",
  })
Run Code Online (Sandbox Code Playgroud)

然后,我发生了以下onChange事件,该事件将输入字段的名称设置为键,将值或检查状态设置为值。在这里看到的

const onChange = (e) => {
    if (e.target.type === 'checkbox' && !e.target.checked) {
        setFormState({...formState, [e.target.name]: e.target.checked});
    } else {
        setFormState({...formState, [e.target.name]: e.target.value });
    }
 }
Run Code Online (Sandbox Code Playgroud)

这是我的表格

<form onSubmit={submitForm}>
      {/* <input type="text" name="package" value={data.datoCmsPricing.title} /> */}
      <label>
        Name
        <input
          type="text"
          name="name"
          value={formState.name}
          onChange={onChange}
        />
      </label>
      <label>
        Email
        <input
          type="email"
          name="email"
          value={formState.email}
          onChange={onChange}
        />
      </label>
      <label>
        Subject
        <input
          type="text"
          name="subject"
          value={formState.subject}
          onChange={onChange}
        />
      </label>
      <div>
        <h3>Reasons for wanting to train</h3>
        <label>
        Weight Loss
        <input 
          type="checkbox"
          name="weightLoss"
          checked={formState.weightLoss}
          onChange={onChange}
        />
        </label>
        <label>
        Strength 
        <input 
          type="checkbox"
          name="strength"
          checked={formState.strength}
          onChange={onChange}
        />
        </label>
        <label>
        Sport 
        <input 
          type="checkbox"
          name="sport"
          checked={formState.sport}
          onChange={onChange}
        />
        </label>
      </div>

      <label>
        message
        <textarea
          name="message"
          value={formState.message}
          onChange={onChange}
        />
      </label>
      <button type="submit">Submit</button>
    </form>
Run Code Online (Sandbox Code Playgroud)

然后我将它发送到我的 lamdba 函数

  const response = await fetch("/.netlify/functions/sendmail", {
       method: "POST",
       body: JSON.stringify(formState),
     })
Run Code Online (Sandbox Code Playgroud)

现在,在发送到 lamdbda 函数并被解析后,我的状态在 json 中看起来如下所示

{ 
  name: 'Anders',
  package: 'silver',
  email: 'email@email.com',
  subject: 'fdsafa',
  weightLoss: 'on',
  strength: 'on',
  sport: 'on',
  message: 'fdsafasf'
} 
Run Code Online (Sandbox Code Playgroud)

现在我想让我的初始状态看起来像 sendgird 想要的格式,所以这就是我尝试的状态设置。

const [formState, setFormState] = React.useState({
    name: "",
    package: `${data.datoCmsPricing.title}`,
    email: "",
    subject: "",
    weightLoss:"",
    strength:"",
    sport:"",
    message: "",
    data:{
      reasonArray:[
        {
          reason:""
        },
        {
          reason:""
        }
      ]
    }
  })
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用以下内容更新已检查值的 onChange 事件,我还更新了我的表单,以便它获取用户友好的名称。见下面这段代码

 const onChange = (e) => {
    if (e.target.type === 'checkbox' && !e.target.checked) {
        setFormState({...formState, data:{ reasonArray:[ { reason:e.target.reason}, ]}});
    } 
    ...
 }
Run Code Online (Sandbox Code Playgroud)

表格变更

  ...
     <label>
        Weight Loss
        <input 
          type="checkbox"
          name="weightLoss"
          reason="weightLoss"
          checked={formState.weightLoss}
          onChange={onChange}
        />
        </label>
        <label>
        Strength 
        <input 
          type="checkbox"
          name="strength"
          reason="strength"
          checked={formState.strength}
          onChange={onChange}
        />
        </label>
        <label>
        Sport 
        <input 
          type="checkbox"
          name="sport"
          reason="sport"
          checked={formState.sport}
          onChange={onChange}
        />
        </label>
   ...
Run Code Online (Sandbox Code Playgroud)

经过我的尝试,我在 Post 请求后得到的结果 Json 是这样的。它不更新数据部分。所以生成的 Json 格式正确,但没有附加原因。提前感谢您的帮助。

{ 
   "name":"Anders",
   "package":"Silver",
   "email":"email@email.com",
   "subject":"fdsaf",
   "weightLoss":"on",
   "strength":"on",
   "sport":"on",
   "message":"fdsafas",
   "data":{ 
      "reasonArray":[ 
         { 
            "reason":""
         },
         { 
            "reason":""
         }
      ]
   }
}
Run Code Online (Sandbox Code Playgroud)

尝试拉比的回答

  ...

 const prepareDataForApi = (formData) => {
  const newFormData = Object.assign({}, formData); // optional if passed cloned copy of formData object or you can also use lodash cloneDeep
  newFormData.data = {
    reasonArray:[]
  };

  Object.keys(newFormData.reasons).forEach(key => {
    if(newFormData.reasons[key]){
      newFormData.data.reasonArray.push({reason: key})
    }
  });

  delete newFormData.reasons;

  return newFormData;
}



 const submitForm = async (e) => {
  e.preventDefault();

  setForm(false);



  // const newFormData = prepareDataForApi(formData); 
     const newFormData = prepareDataForApi(formState);

  console.log(newFormData);

...
Run Code Online (Sandbox Code Playgroud)

小智 4

1.保持初始状态如下:

{ 
   "name":"Anders",
   "package":"Silver",
   "email":"email@email.com",
   "subject":"fdsaf",
   "message":"fdsafas",
   "reasons": {
      "weightLoss": true,
      "strength": true,
      "sport": true,
   }
}
Run Code Online (Sandbox Code Playgroud)
  1. 修改onChange():
 const onChange = (e) => {
    if (e.target.type === 'checkbox') {
        const changedReason = e.target.getAttribute('name');
        setFormState({...formState, reasons:{...formState.reasons, [changedReason]: !formState.reasons[changedReason]}});
    } 
    ...
 }

Run Code Online (Sandbox Code Playgroud)
  1. 更改表格onSubmit()

    在调用 api 之前,调用转换器函数,它将转换formState为 lambda 函数所需的 JSON 格式

const prepareDataForApi = (formData) => {
  const newFormData = Object.assign({}, formData); // optional if passed cloned copy of formData object or you can also use lodash cloneDeep
  newFormData.data = {
    reasonArray:[]
  };

  Object.keys(newFormData.reasons).forEach(key => {
    if(newFormData.reasons[key]){
      newFormData.data.reasonArray.push({reason: key})
    }
  });

  delete newFormData.reasons;

  return newFormData;
}
Run Code Online (Sandbox Code Playgroud)