如何更新嵌套在React状态的对象

时间:2019-07-04 18:24:11

标签: javascript arrays reactjs typescript

我有一个在React状态下更新嵌套对象的函数,并且有一个可行的解决方案,但我正在寻找更精致的东西。

这是我的状态结构:

state: {
  ...someState,
  object: [
      {
        key1: "1",
        key: "2",
        key3: "3",
        key4: "4"},
      {
        key1: "1",
        key: "2",
        key3: "3",
        key4: "4"}]
    }

当前我正在使用此功能来更新状态:

handleInputChange = (
    e: ChangeEvent<HTMLInputElement>,
    name: FilterKeys,
    subname?: any,
    index?: number
  ) => {
    e.persist();

      if (subname && index !== undefined) {
        let prop: SomeKeys;
        prop = subname;
        const editedObject = Object.assign({}, this.state.object);
        editedObject[index][prop] = e.target.value;
        const object = Object.keys(editedObject).map((e: any) => {
          return editedObject[e];
        });
        this.setState(
          (prevState: I) => ({
            ...prevState,
            object
          }),
          () => {
            this.someCallback()
          }
        );

    }
  };

我的目标是做这样的事情:

 handleInputChange = (
    e: ChangeEvent<HTMLInputElement>,
    name: FilterKeys,
    subname?: any,
    index?: number
  ) => {
    e.persist();

      if (subname && index !== undefined) {
        let prop: SomeKeys;
        prop = subname;
        this.setState((prevState)=>{
          object: [...prevState.object, prevState.object[index][prop]:3]
})
}

    }
  };

希望您能理解我的意思。我也知道一种解决方案,可以在其中分配一些键给对象,这样我就可以访问它,但是我对这样的语法很感兴趣,因为imo看起来更干净

p.s对象数组的长度取决于用户

3 个答案:

答案 0 :(得分:0)

您可以使用第三方库吗? 我推荐https://lodash.com/docs/4.17.11#set。由于您需要具有不可变的状态,因此可以使用lodash / fp(https://github.com/lodash/lodash/wiki/FP-Guide):

import set from 'lodash/fp/set'

//...
this.setState(
  currentState => set(['object', index, prop], e.target.value, currentState)
)

set是lodash.fp函数。第一个参数是要设置的属性的路径,第二个参数是新值,第三个参数是要更新的对象。 Lodash / fp总是创建一个NEW对象。

如果您了解函数式编程的用法,则可以将这种构造简化为

this.setState(
      set(['object', index, prop], e.target.value)
    )

另一种解决方案

当然,您可以在没有外部库的情况下做到这一点:

this.setState(prevState => ({
    ...prevState,
    object: [
        ...prevState.object.slice(0, index),
        {
            ...prevState.object[index],
            [prop]: e.target.value,
        },
        ...prevState.object.slice(index + 1),
    ],    
}))

答案 1 :(得分:0)

仅从key3更新object[0]

const newState = {
    ...state,
    object:[
        ...state.object,
        [0] : {
            ...state.object[0],
            key3: newValue
        }
    ]
}

答案 2 :(得分:0)

虽然没有您希望的那么简洁,但是我认为这应该可以解决问题。

它将原始数组映射为新对象的数组,如果索引与当前迭代匹配,则它将给定“键”的值覆盖为事件目标的值。

handleInputChange = (
  e: ChangeEvent<HTMLInputElement>,
  name: FilterKeys,
  subname?: any,
  index?: number
) => {
  e.persist();

  if (subname && index !== undefined) {
    const prop: SomeKeys = subname;
    const newObjArray = this.state.object
      .map((obj, i) =>  ({
        ...obj,
        [prop]: i !== index ? obj[prop] : event.target.value
      }));

    this.setState((prevState)=>{
      object: newObjArray
    });
  }
}