简体   繁体   English

ReactJS:如何使用动态键访问和更新嵌套状态对象?

[英]ReactJS: How to access and update nested state object with dynamic key?

Suppose I have a component with state defined as follows:假设我有一个状态定义如下的组件:

this.state = {
    apple:{
        a:1,
        b:2,
    },
    mango:{
        banana : {
            a:1,
            b:2,
        }
    }
}

If I wanted to update the value of a nested object in my state, I could do so with hard coded keys as shown below:如果我想在我的状态中更新嵌套对象的值,我可以使用硬编码的键来完成,如下所示:

cost temp =  { ...this.state['mango'] }
temp['banana']['a'] = 2;

this.setState({mango:temp});

How would I update a nested value in my state object dynamically key?如何动态更新状态对象中的嵌套值? For example, if I had a JSON path in either dot or array notation, how could I update my component state?例如,如果我有一个点或数组表示法的 JSON 路径,我该如何更新我的组件状态?

One way to achieve this would be to acquire the nested object that is the parent of the field that your path is targeting via Array#reduce : 实现此目的的一种方法是通过Array#reduce获取嵌套对象,该对象是路径所针对的字段的父对象:

const nestedObject = path
.slice(0, -1)
.reduce((object, part) => (object === undefined ? undefined : object[part]), { ...state })

And then update the last key/value of nestedObject by via the last key of your path: 然后通过路径的最后一个键更新nestedObject的最后一个键/值:

/* Get last part of path, and update nestedObject's value for this key, to 2 */
const [pathTail] = path.slice(-1);    
nestedObject[pathTail] = 2;

The following snippet shows these two ideas together: 以下代码片段将这两个想法结合在一起:

 /* Path of nested field to update, in array notation */ const path = ['mango', 'banana', 'a']; /* Components state */ const state = { apple: { a: 1, b: 2, }, mango: { banana: { a: 1, b: 2, } } }; const stateClone = { ...state }; /* Aquire the parent object (ie banana) of the target field (ie a) */ const nestedObject = path .slice(0, -1) .reduce((object, part) => (object === undefined ? undefined : object[part]), stateClone) if (nestedObject !== undefined) { /* Obtain last key in path */ const [pathTail] = path.slice(-1); /* Update value of last key on target object to new value */ nestedObject[pathTail] = 2; } /* Display updated state */ console.log('Updated state:', stateClone) /* Call this.setState: */ // this.setState(stateClone); 

Update 更新资料

Here is some extra detail outlining how the reduce() part of the answer works: 这里是一些额外的细节,概述了答案的reduce()部分是如何工作的:

path
/* slice obtains ['mango', 'banana'], seeing -1 clips last item */
.slice(0, -1)  
/* reduce iterates through each part of array ['mango', 'banana']
where at each iteration we fetch the corresponding nested object 
of the { ...state } object that's passed in */
.reduce((object, part) => {

/* At iteration 1: 
object has two keys, 'apple' and 'mango'
part is 'mango'
object is defined, so return object['mango'] for first iteration

At iteration 2:
object passed from last iteration has one key, 'banana'
part is 'banana'
object is defined, so return object['banana'] for second iteration

Reduce complete:
we return object['banana'], which is the same as state['mango']['banana']
*/

if(object === undefined) { return undefined; }

return object[part]

}, stateClone)

Having:拥有:

 const [formState, setFormState] = useState(
      {
        id:1,
        name:'Name',
        innerObjectName: {
            propA: 'Something',
            propB: 'Another thing',
        }
      });

Maybe you're looking for something like this:也许你正在寻找这样的东西:

   const handleComplexInputChange = (evt, object) => {
      setFormState({
         ...formState,
         [object] : {
            ...formState[object],
            [evt.target.name]: evt.target.value,
         }
      })
   } 

And from your component you should call it like this:从您的组件中,您应该像这样调用它:

   onChange={(e) => {
        handleComplexInputChange(e, "innerObjectName");
   }}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM