Javascript 使用状态钩子。单击复选框时,如何使用数组更新json对象的状态
我通过lamda服务器将状态作为字符串化变量从表单发送到POST请求,然后lamda服务器解析状态并将状态发送到sendgrid,我在那里使用send grids模板功能。这要求我将json格式化为这样,以便循环一个特定部分(多个复选框),所有这些部分都应该具有相同的键,但具有不同的值,由表单中的Javascript 使用状态钩子。单击复选框时,如何使用数组更新json对象的状态,javascript,json,reactjs,handlebars.js,react-hooks,Javascript,Json,Reactjs,Handlebars.js,React Hooks,我通过lamda服务器将状态作为字符串化变量从表单发送到POST请求,然后lamda服务器解析状态并将状态发送到sendgrid,我在那里使用send grids模板功能。这要求我将json格式化为这样,以便循环一个特定部分(多个复选框),所有这些部分都应该具有相同的键,但具有不同的值,由表单中的reason=“Weight Loss”设置。下面是最终json的形成方式 { "name" :"anders", "message" : "winfsdafasfdsfsadfsadnipeg
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>
然后,我有了下面的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>
现在,在发送到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>
...
拉比的回答
...
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);
...
更新密钥时,新的
onChange
似乎没有替换所有嵌套值。请尝试以下方法:
setFormState({
…formState,
数据:{
…formState.data,//保留来自上一个数据对象的键(如果它只包含您正在指定的键,则不需要)
reasonArray:[
…formState.data.reasonArray,//保留来自reasonArray的以前条目
{原因:e.target.reason},
]
}
});
另一种方法是使用效果
const[formState,setFormState]=React.useState({…}):
//每次减肥改变时都会跑步
React.useffect(()=>{
让newReasonArray
if(formState.失重){
newReasonArray=[…formState.reasonArray];//所以我们不改变状态
push({reason:'weightLoss'});
}否则{
//如果要将其从阵列中移除,请取消选中它
newReasonArray=[…formState.reasonArray];
newReasonArray.filter((reason)=>(reason.reason!=“失重”);
}
console.log(newReasonArray)//测试其更新是否正确
//设置新数组的状态
setFormState({…formState,数据:{reasonArray:newReasonArray}});
},[formState.失重];
1.保持初始状态如下:
{
"name":"Anders",
"package":"Silver",
"email":"email@email.com",
"subject":"fdsaf",
"message":"fdsafas",
"reasons": {
"weightLoss": true,
"strength": true,
"sport": true,
}
}
onSubmit()
:
在调用api之前,调用converter函数,该函数将formState
转换为lambda函数所需的JSON格式
const response = await fetch("/.netlify/functions/sendmail", {
method: "POST",
body: JSON.stringify(formState),
})
嗯,我得到了一个
\uuuu proto\uuu:Object
,其中数据{Reason…
应该去。我得到的是一个reasonArray没有定义,我一定是在某个地方搞砸了。嗯,我的Reason
的值仍然是空的。你是在尝试添加到原因数组中?还是尝试修改当前值?我想两者都做。我想我必须让数组处于启动状态。但是如果我可以在后面添加数组,并更改reason
的值,这将是理想的。如果这有意义,我希望reason更改为Weight Loss
或Sport
的值,这一切取决于复选框中选中的内容。但它需要中间的空格(取决于)因此,它在结尾的电子邮件中更具可读性。我是将prepareDataForApi函数放在表单提交处理程序的外部还是内部?然后我将console.log(newFormData)用于测试?将其放在提交处理程序的外部,只需调用prepareDataForApi
内部提交处理程序,类似这样:`prepareDataForApi=()=>{func def…}onSubmit=()=>{const newFromData=prepareDataForApi(formData);console.log(newFromData);}`do I控制台日志newFormData
内部如下prepareDataForApi=()=>{console.log(newFormData);}
?如果您想在浏览器控制台中打印newFromData,可以这样做。是的,我只想在进入下一步之前先调试一下。我会试试的
...
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);
...
{
"name":"Anders",
"package":"Silver",
"email":"email@email.com",
"subject":"fdsaf",
"message":"fdsafas",
"reasons": {
"weightLoss": true,
"strength": true,
"sport": true,
}
}
const onChange = (e) => {
if (e.target.type === 'checkbox') {
const changedReason = e.target.getAttribute('name');
setFormState({...formState, reasons:{...formState.reasons, [changedReason]: !formState.reasons[changedReason]}});
}
...
}
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;
}