我有一个带有表单的react组件。我将表单设置保留在组件外部的对象中:
const initialForm = {
name: {
elementType: 'input',
elementAtts: {
label: 'Tenant Name',
readOnly: false
},
isRequired : true,
value: '',
},
description: {
elementType: 'input',
elementAtts: {
label: 'Description',
readOnly: false
},
isRequired : false,
value: '',
}
}
const AddAndDisplay = (props) =>
{
const [formSettings, setFormSettings] = useState(initialForm);
...
}
elementAtts
是我通过输入的属性。
我想做的是打开一个显示表单的模式-一次仅用于显示,一次允许进行编辑-可以用于编辑现有项或添加新项。
我这样做是为了编辑现有项目并显示:
//a callback
const OpenModalForEditOrDisplay = (isEditable, cardObject) =>
{
setFormSettings(prevForm =>
{
let newForm = {...prevForm};
newForm.name.elementAtts.readOnly = !isEditable;
newForm.description.elementAtts.readOnly = !isEditable;
return {...newForm}
});
setIsFormOpen(true);
}
};
并添加新项目:
setFormSettings(initialForm);
setIsEditing(true);
setIsFormOpen(true); //this is merely a state saying if to show the modal with the form
然后用户可以提交或取消表单,无论哪种情况,我都在做
setFormSettings(initialForm);
问题是initialForm
似乎已被覆盖,如果我仅打开表单以进行显示,则尝试打开表单进行添加时它将保持显示状态,因为编辑部分的代码改变了我的想法将是initialForm
的副本。如果我在开放式编辑功能中删除了这些行,则表单将保留初始表单的设置:
newForm.name.elementAtts.readOnly = !isEditable;
newForm.description.elementAtts.readOnly = !isEditable;
为什么这里要覆盖初始形式?
答案 0 :(得分:1)
您已使用Spread语法在setFormSettings中克隆prevForm值。但是,您必须注意,Spread语法仅浅层克隆对象,而不会执行深层克隆,这意味着您在prevForm中嵌套的值仍保留原始引用,并且在更新诸如
这样的值时newForm.name.elementAtts.readOnly = !isEditable;
newForm.description.elementAtts.readOnly = !isEditable;
您要按照原始参考对其进行变异。更新状态的正确方法是通过克隆每个嵌套级别来不变地更新状态,例如
setFormSettings(prevForm =>
{
let newForm = {
...prevForm,
name: {
...prevForm.name,
elementAttrs: {
...prevForm.name.elementAttrs,
readOnly: !isEditable,
}
}
description: {
...prevForm.description,
elementAttrs: {
...prevForm.description.elementAttrs,
readOnly: !isEditable,
}
}
};
return newForm;
});
答案 1 :(得分:0)
这是深层复制和浅层复制的问题。 “ formSettings”数据源是“ initialForm”。使用'setFormSettings'将更改为'initialForm',这是正确的。因为在初始化时使用浅表副本。您可以使用功能Deep Deep复制到'initialForm'。
const createInitialForm = () => ({
name: {
elementType: 'input',
elementAtts: {
label: 'Tenant Name',
readOnly: false
},
isRequired : true,
value: '',
},
description: {
elementType: 'input',
elementAtts: {
label: 'Description',
readOnly: false
},
isRequired : false,
value: '',
}
})
const AddAndDisplay = (props) =>
{
const [formSettings, setFormSettings] = useState(createInitialForm());
...
}