簡體   English   中英

如何在Typescript中的嵌套對象中復制帶有更新的對象?

[英]How to copy objects with updates in nested objects in Typescript?

我有一個 React 組件,其中包含一些表單字段:

<TextField
  label="Description"
  id="description"
  value={company.companyDescription}
  onChange={updateFormField("companyDescription")}
></TextField>

以及在值發生變化時更新我公司狀態的函數:

const updateFormField = (property: string) => (event: ChangeEvent<HTMLInputElement>) => {
  setCompany(prev => ({ ...prev, [property]: event.target.value }))
}

這意味着每當表單字段更改時,我都想創建舊對象的新副本(因此是擴展運算符)。

我的問題是 company 有嵌套的屬性,比如company.location.address

{
  name: "some company",
  location: {
    address: "some street"
  }
  // ...
}

有沒有辦法重構上面的函數來更新嵌套的屬性? 例如類似的東西:

const updateFormField = (property: string[]) => (event: ChangeEvent<HTMLInputElement>) => {
  setCompany(prev => ({ ...prev, [...property]: event.target.value }))
}

我不認為有一個特別巧妙的解決方案,但是應該可以循環選擇/添加新路徑:

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
  )}
}

相同方法的普通 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() 和動態查找內部引用應該可以做到。 我假設上面的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM