主要编辑
我有一个非常大的物体,深度为 3 级。我使用它作为模板在页面上生成组件并存储稍后使用的值,例如:
obj =
{
"group": {
"subgroup1": {
"value": {
"type": "c",
"values": []
},
"fields_information": {
"component_type": "table",
"table_headers": [
"label",
"size"
],
}
},
"subgroup2": {
"value": {
"type": "c",
"values": []
},
"fields_information": {
"component_type": "table",
"table_headers": [
"label",
"size"
],
}
},
},
}
多亏了这一点,我可以动态生成视图,该视图作为模板存储在数据库中。
我正在为两件事而苦苦挣扎。首先,根据用户输入的文本框、复选框等更新值。 我是这样做的:
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: ""}, {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: ""}, {label: "", size: ""}, {label: "", size: ""}]}}}}
toggleObj(temp)
}
}, [])
return (
//draw the array
)
}
请参考 CustomTable 组件。 与上面的示例对象一样,我有 2 个要打印的自定义表。不幸的是,一个应该工作的 useEffect 工作不正常。我正在观察,该值字段仅针对 Obj 中的最后一个“表”设置。当我做 obj 的浅拷贝时,它工作正常。但我担心将来可能发生的任何影响。
我对使用 createContext 也完全陌生,也许这就是问题所在。
感谢任何理解这种混乱的人:)
答案 0 :(得分:1)
主要问题似乎是您没有提供您的上下文。你所拥有的是字面上传递空白对象和 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 以针对实际更新的状态片段,这将有助于在深度克隆状态结构成为实际问题时降低性能成本。