[英]How to copy objects with updates in nested objects in Typescript?
I have a React component that has some form fields in it:我有一个 React 组件,其中包含一些表单字段:
<TextField
label="Description"
id="description"
value={company.companyDescription}
onChange={updateFormField("companyDescription")}
></TextField>
and a function that updates my company state whenever the values change:以及在值发生变化时更新我公司状态的函数:
const updateFormField = (property: string) => (event: ChangeEvent<HTMLInputElement>) => {
setCompany(prev => ({ ...prev, [property]: event.target.value }))
}
This means that whenever a form field changes I'd like to create a new copy (hence the spread operator) of the old object.这意味着每当表单字段更改时,我都想创建旧对象的新副本(因此是扩展运算符)。
My problem is that company has nested properties in it, like company.location.address
:我的问题是 company 有嵌套的属性,比如
company.location.address
:
{
name: "some company",
location: {
address: "some street"
}
// ...
}
Is there a way to refactor the above function to update the nested properties?有没有办法重构上面的函数来更新嵌套的属性? For example something like:
例如类似的东西:
const updateFormField = (property: string[]) => (event: ChangeEvent<HTMLInputElement>) => {
setCompany(prev => ({ ...prev, [...property]: event.target.value }))
}
I don't think there's a particularly neat solution to this, however it should be possible to loop through selecting/adding the new path:我不认为有一个特别巧妙的解决方案,但是应该可以循环选择/添加新路径:
const updateFormField = (property: string[]) => (event: ChangeEvent<HTMLInputElement>) => {
setCompany(prev => {
// Take a copy of the state
const newObj = { ...prev }
// Set up a refernce to that object
let selected = newObj
// Loop through each property string in the array
for (let i = 0; i < property.length; i++) {
// If we're at the end of the properties, set the value
if (i === property.length - 1) {
selected[property[i]] = event.target.value
} else {
// If the property doesn't exist, or is a value we can't add a new property to, set it to a new object
if (typeof selected[property[i]] !== 'object') {
selected[property[i]] = {}
}
// Update our refernce to the currently selected property and repeat
selected = selected[property[i]]
}
}
// Return the object with each nested property added
return newObj
)}
}
Plain JS working example of the same method:相同方法的普通 JS 工作示例:
const test = (prev, property, value) => { const newObj = { ...prev } let selected = newObj for (let i = 0; i < property.length; i++) { if (i === property.length - 1) { selected[property[i]] = value } else { if (typeof selected[property[i]] !== 'object') { selected[property[i]] = {} } selected = selected[property[i]] } } return newObj } console.log(test( {"a": "1"}, ["b", "c", "d"], 100 )) console.log(test( {"a": "1"}, ["a", "b"], 100 )) console.log(test( {"a": {"b": {"c": 1}}}, ["a", "b", "c"], 100 ))
Object.assign() and dynamically finding the inner reference should do it. Object.assign() 和动态查找内部引用应该可以做到。 I'm assuming the input type of string[] above indicates the nested path is an array like ['company', 'location', 'address']:
我假设上面的 string[] 输入类型表示嵌套路径是一个数组,如 ['company', 'location', 'address']:
const updateFormField = (property: string[]) => (event: ChangeEvent<HTMLInputElement>) => {
setCompany(prev => {
const copy = Object.assign({}, prev);
let ref = copy;
for (let i = 0; i < property.length - 1; i++) {
ref = ref[property[i]];
}
ref[property[property.length - 1]] = event.target.value
return copy;
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.