如何解决嵌套对象的状态更新方法问题
主要编辑
我有一个非常大的物体,深度为 3 级。我使用它作为模板在页面上生成组件并存储稍后使用的值,例如:
obj =
{
"group": {
"subgroup1": {
"value": {
"type": "c","values": []
},"fields_information": {
"component_type": "table","table_headers": [
"label","size"
],}
},"subgroup2": {
"value": {
"type": "c",},}
多亏了这一点,我可以动态生成视图,该视图作为模板存储在数据库中。
我正在为两件事而苦苦挣扎。首先,根据用户输入的文本框、复选框等更新值。 我是这样做的:
const updateObj = (group,subgroup,value) => {
let tempObj = {...obj}
tempObj[group][subgroup].value.value = value
toggleObj(tempObj)
}
我知道扩展运算符实际上并没有进行深复制。但是,它允许我处理对象并稍后保存。这是一个问题吗?我是否必须 cloneDeep 或者它很好? cloneDeep 会影响性能吗?
下面描述第二种情况
export const ObjectContext = React.createContext({
obj: {},toggleObj: () => {},});
export const Parent = (props) => {
const [obj,toggleObj] = useState()
const value = {obj,toggleObj}
return (
<FormCreator />
)
}
const FormCreator = ({ catalog }) => {
const {obj,toggleObj} = React.useContext(ObjectContext)
return (<>
{Object.keys(obj).map((sectionName,sectionIdx) => {
const objFieldsinformation = sectionContent[keyName].fields_information
const objValue = sectionContent[keyName].value
...
if (objFieldsinformation.component_type === 'table') {
return (
<CustomTable
key={keyName + "id"}
label={objFieldsinformation.label}
headers={objFieldsinformation.table_headers}
suggestedValues={[{label: "",size: ""},{label: "",size: ""}]}
values={objValue.values}
sectionName={sectionName}
keyName={keyName}/>
)
}
...
})}
</>)
}
const CustomTable= (props) => {
const { label = "",headers = [],suggestedValues = [],values,readOnly = false,sectionName,keyName } = props
const {obj,toggleObj} = React.useContext(ObjectContext)
//this one WORKS
useEffect(() => {
if (obj[sectionName][keyName].value.type === "complex") {
let temp = {...obj}
temp[sectionName][keyName].value.values = [...suggestedValues]
toggleObj(temp)
}
},[])
//this one DOES NOT
useEffect(() => {
if (obj[sectionName][keyName].value.type === "c") {
let temp = {...obj,[sectionName]: {...obj[sectionName],[keyName]: {...obj[sectionName][keyName],value: {...obj[sectionName][keyName].value,values: [{label: "",size: ""}]}}}}
toggleObj(temp)
}
},[])
return (
//draw the array
)
}
请参考 CustomTable 组件。 与上面的示例对象一样,我有 2 个要打印的自定义表。不幸的是,一个应该工作的 useEffect 工作不正常。我正在观察,该值字段仅针对 Obj 中的最后一个“表”设置。当我做 obj 的浅拷贝时,它工作正常。但我担心将来可能发生的任何影响。
我对使用 createContext 也完全陌生,也许这就是问题所在。
感谢任何理解这种混乱的人:)
解决方法
主要问题似乎是您没有提供您的上下文。你所拥有的是字面上传递空白对象和 void 返回函数。因此为什么调用它没有实际效果,但改变值却有。
export const ObjectContext = React.createContext({
obj: {},toggleObj: () => {},});
export const Parent = (props) => {
const [obj,toggleObj] = useState({})
const value = {obj,toggleObj}
return (
<ObjectContext.Provider value={value}>
<FormCreator />
</ObjectContext.Provider>
)
}
理想情况下,您还可以让上述组件环绕 FormCreator
并将其呈现为 props.children
。这是为了防止每次调用 toggleObj
时都重新渲染整个子树。请参阅 first part of this tutorial 以了解典型模式。
关于改变状态的问题,在 React 中保持状态不可变是绝对重要的——至少,如果你正在使用 useState
或某种减速器。 Stack Overflow 上经常会出现由状态突变引起的错误,事实上我最近做了一个 codesandbox 来演示一些更常见的错误。
我也同意@SamuliHakoniemi 的观点,像这样的深度嵌套对象实际上更适合 useReducer
钩子,甚至可能更进一步并建议这里需要像 Redux 这样的适当状态管理库。它将允许您细分 reducer 以针对实际更新的状态片段,这将有助于在深度克隆状态结构成为实际问题时降低性能成本。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。