【发布时间】:2021-04-30 17:47:01
【问题描述】:
主要编辑
我有一个非常大的物体,深度为 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"
],
}
},
},
}
多亏了这一点,我可以动态生成视图,该视图作为模板存储在 DB 中。
我在两件事上苦苦挣扎。首先,根据用户输入的文本框、复选框等更新值。 我是这样做的:
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 个要打印的 CustomTables。不幸的是,一个应该工作的 useEffect 不能正常工作。我观察到,该值字段仅为 Obj 中的最后一个“表”设置。当我做 obj 的浅拷贝时,它工作正常。但我担心将来可能会发生任何影响。
我对使用 createContext 也完全陌生,也许这就是问题所在。
感谢任何理解这种混乱的人:)
【问题讨论】:
-
您的问题不清楚 - 首先,
subGroup是一个数组,因此[subGroup].value应该始终未定义。但是您的最后两个示例也几乎相同,除了第二个是可变的(并且您访问values与items),所以当您说一个有效但另一个无效时,我不知道您的意思。不必要的状态变化不可避免地会在以后导致静默错误 - 例如,如果您有依赖于subGroup的效果或记忆组件,则当该组的value.values发生突变时,它将不会运行。 -
@lawrence-witt 我只是把它作为一个参考例子。我对设置 undefined 等没有任何问题(提供的示例可能搞砸了)。我可以先提到“不可避免地会导致无声的错误”。可以?我正在制作用 const [obj, toggleObj] = useState() 定义的对象的“副本”,我正在更新 tempObj(它也在更新 obj),但我用 toggleObj 更新了状态,实际上它正在覆盖 obj。那么刚才obj的突变有关系吗?
-
此外,我所做的大约 2 种更新(后一种有效)是我主要关心的问题。在触发 toggleObj 之前,我将正确的变异 obj 分配给 var 并在之前将其打印出来,并且看起来符合要求。但是,在祖父母中,当我尝试使用 useEffect(()=>{}) 监视所需对象的更改时,实际上什么也没发生。我想以这种方式呈现 3 个表格,并且行仅对最后一个可见。我认为描述它有点复杂。我会尝试用所有组件做一个正确的例子。
-
只是一个旁注,但当状态结构具有更多复杂性/深度时,我个人更喜欢使用 useReducer 而不是 useState。
标签: reactjs clone use-state createcontext