【问题标题】:ReactJS: How to access and update nested state object with dynamic key?ReactJS:如何使用动态键访问和更新嵌套状态对象?
【发布时间】:2019-10-06 12:33:27
【问题描述】:

假设我有一个状态定义如下的组件:

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

如果我想在我的状态下更新嵌套对象的值,我可以使用如下所示的硬编码键来执行此操作:

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

this.setState({mango:temp});

如何动态更新状态对象中的嵌套值?例如,如果我有一个点或数组表示法的 JSON 路径,我如何更新我的组件状态?

【问题讨论】:

  • 如何提供输入以便您可以动态访问这些键?
  • 使用点符号或数组

标签: javascript reactjs ecmascript-6


【解决方案1】:

实现此目的的一种方法是通过Array#reduce 获取作为路径所针对的字段的父级的嵌套对象:

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

然后通过路径的最后一个键更新nestedObject 的最后一个键/值:

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

下面的sn-p将这两个想法一起展示:

/* 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);

更新

这里有一些额外的细节概述了答案的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)

【讨论】:

  • 你是很棒的兄弟,你能再帮我一个忙吗?请在你的例子中解释一下reduce函数
  • 不客气,很高兴我能帮上忙!当然,我会更详细地更新我的答案:-)
  • 它工作正常,但状态的变化在我为任何其他变量设置状态之前不会反映出来
  • 是的,您需要将上面的stateClone 对象传递给setState() 以使组件根据新状态进行更新
  • 是的,现在它与状态克隆一起工作正常,它的速度也提高了
【解决方案2】:

拥有:

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

也许你正在寻找这样的东西:

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

从你的组件中你应该这样称呼它:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 2011-10-25
    • 2018-11-26
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    相关资源
    最近更新 更多