React 对象的初始状态被覆盖
React object initial state is overriden
我得到了一个带有表单的 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;
为什么初始表单在这里被覆盖了?
您已经使用 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;
});
这是深拷贝和浅拷贝的问题。 'formSettings' 数据源是 'initialForm'。使用 'setFormSettings' 将更改为 'initialForm' ,这是对的。因为你初始化的时候用的是浅拷贝。您可以使用函数深度复制到 '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());
...
}
我得到了一个带有表单的 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;
为什么初始表单在这里被覆盖了?
您已经使用 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;
});
这是深拷贝和浅拷贝的问题。 'formSettings' 数据源是 'initialForm'。使用 'setFormSettings' 将更改为 'initialForm' ,这是对的。因为你初始化的时候用的是浅拷贝。您可以使用函数深度复制到 '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());
...
}