我正在通过 lamda 服务器将我的状态作为stringified
变量从表单发送到 POST 请求,然后 lamda 服务器对其进行解析并将其发送到我正在使用发送网格模板功能的 sendgrid。这需要我像这样格式化 json 以便循环访问一个特定部分(多个复选框(,这些部分都应该具有相同的键但不同的值,由表单中的reason="Weight Loss"
设置。以下是最终 json 需要形成的方式。
{
"name" :"anders",
"message" : "winfsdafasfdsfsadfsadnipeg",
"package" : "silver",
"email" : "email@email.com",
"subject" : "fdsafas",
"data":{
"reasonArray":[
{
"reason":"weightLoss"
},
{
"reason":"Sport"
}
]
}
}
然后我可以做一些魔术并循环检查复选框中选中的原因
<ol>
{{#each data.reasonArray}}
<li>{{this.reason}} </li>
{{/each}}
</ol>
现在,如果我使用单个键值对离开状态并且没有data
部分,我就可以工作了。 这是我的初始状态
const [formState, setFormState] = React.useState({
name: "",
package: `${data.datoCmsPricing.title}`,
email: "",
subject: "",
weightLoss:"",
strength:"",
sport:"",
message: "",
})
然后,我有以下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 });
}
}
这是我的表格
<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>
然后我把它发送到我的 lamdba 函数
const response = await fetch("/.netlify/functions/sendmail", {
method: "POST",
body: JSON.stringify(formState),
})
现在我的状态在被发送到 lamdbda 函数并被解析后在 json 中看起来像下面这样
{
name: 'Anders',
package: 'silver',
email: 'email@email.com',
subject: 'fdsafa',
weightLoss: 'on',
strength: 'on',
sport: 'on',
message: 'fdsafasf'
}
现在,我希望我的初始状态看起来像 sendgird 想要的格式,所以这就是我在状态设置中尝试的。
const [formState, setFormState] = React.useState({
name: "",
package: `${data.datoCmsPricing.title}`,
email: "",
subject: "",
weightLoss:"",
strength:"",
sport:"",
message: "",
data:{
reasonArray:[
{
reason:""
},
{
reason:""
}
]
}
})
然后我尝试使用以下方法更新已检查值的onChange事件,我还更新了我的表单,以便它获取一个用户友好的名称。在下面看到这个代码
const onChange = (e) => {
if (e.target.type === 'checkbox' && !e.target.checked) {
setFormState({...formState, data:{ reasonArray:[ { reason:e.target.reason}, ]}});
}
...
}
表单更改
...
<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>
...
我在 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":""
}
]
}
}
尝试拉比的回答
...
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);
...
1.保持你的初始状态如下:
{
"name":"Anders",
"package":"Silver",
"email":"email@email.com",
"subject":"fdsaf",
"message":"fdsafas",
"reasons": {
"weightLoss": true,
"strength": true,
"sport": true,
}
}
- Modify onChange((:
const onChange = (e) => {
if (e.target.type === 'checkbox') {
const changedReason = e.target.getAttribute('name');
setFormState({...formState, reasons:{...formState.reasons, [changedReason]: !formState.reasons[changedReason]}});
}
...
}
- 更改表单的
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;
}
更新键时,新onChange
似乎不会替换所有嵌套值。试试这个:
setFormState({
...formState,
data:{
...formState.data, // keep keys from previous data object (not necessary if it only contains the key you are specifying though)
reasonArray:[
...formState.data.reasonArray, // keep previous entries from reasonArray
{ reason:e.target.reason},
]
}
});
另一种方法是使用effect
.
const [formState, setFormState] = React.useState({...}):
// Runs every time weightLoss is changed
React.useEffect(() => {
let newReasonArray
if (formState.weightLoss) {
newReasonArray = [...formState.reasonArray]; // So we dont mutate state
newReasonArray.push({reason: 'weightLoss'});
} else {
// If you want to remove it from the array if its unchecked
newReasonArray = [...formState.reasonArray];
newReasonArray.filter((reason) => (reason.reason != 'weightLoss'));
}
console.log(newReasonArray) // Test if it is updated correctly
// Set the state with the new array
setFormState({...formState, data: { reasonArray: newReasonArray }});
}, [formState.weightLoss]);