反应setState的深层嵌套值

时间:2019-08-31 11:16:27

标签: javascript reactjs javascript-objects setstate

我的React状态中有一个嵌套很深的对象。目的是更改子节点的值。到应该更新哪个节点的路径已经解决,我使用助手变量在setState中访问该路径。

无论如何,我真的很难在这个嵌套的野兽中执行setState。我在一个Codepen中抽象了这个问题: https://codesandbox.io/s/dazzling-villani-ddci9

在此示例中,我要更改具有changed id的孩子的孩子的def1234属性。

如上所述,给出了路径:固定路径值:Members, skills和可变路径值:Unique Key 1(来自const currentGroupKey,数据中的两个Array位置均来自{{1} }

这是我的状态对象:

const path

我将不胜感激。我已经挣扎了2天:/

2 个答案:

答案 0 :(得分:1)

在使用新的依赖项并必须学习它们之前,您可以编写一个辅助函数来处理更新深层嵌套的值。

我使用以下助手:

//helper to safely get properties
// get({hi},['hi','doesNotExist'],defaultValue)
const get = (object, path, defaultValue) => {
  const recur = (object, path) => {
    if (object === undefined) {
      return defaultValue;
    }
    if (path.length === 0) {
      return object;
    }
    return recur(object[path[0]], path.slice(1));
  };
  return recur(object, path);
};
//returns new state passing get(state,statePath) to modifier
const reduceStatePath = (
  state,
  statePath,
  modifier
) => {
  const recur = (result, path) => {
    const key = path[0];
    if (path.length === 0) {
      return modifier(get(state, statePath));
    }
    return Array.isArray(result)
      ? result.map((item, index) =>
          index === Number(key)
            ? recur(item, path.slice(1))
            : item
        )
      : {
          ...result,
          [key]: recur(result[key], path.slice(1)),
        };
  };
  const newState = recur(state, statePath);
  return get(state, statePath) === get(newState, statePath)
    ? state
    : newState;
};

//use example
const state = {
  one: [
    { two: 22 },
    {
      three: {
        four: 22,
      },
    },
  ],
};
const newState = reduceStatePath(
  state,
  //pass state.one[1],three.four to modifier function
  ['one', 1, 'three', 'four'],
  //gets state.one[1].three.four and sets it in the
  //new state with the return value
  i => i + 1 // add one to state.one[0].three.four
);
console.log('new state', newState.one[1].three.four);
console.log('old state', state.one[1].three.four);
console.log(
  'other keys are same:',
  state.one[0] === newState.one[0]
);

答案 1 :(得分:1)

如果您需要在状态内部更新深度嵌套的属性,则可以使用类似set中的lodash函数,例如:

import set from 'lodash/set'

// ...

handleClick = () => {
  const currentGroupKey = 'Unique Key';
  const path = [1, 1];

  let nextState = {...this.state}

  // as rightly pointed by @HMR in the comments,
  // use an array instead of string interpolation
  // for a safer approach

  set(
    nextState,
    ["group", currentGroupKey, "Members", path[0], "skills", path[1], "changed"],
    "just now"
  );

  this.setState(nextState)
}

这可以解决问题,但是由于set会改变原始对象,因此请确保使用object spread技术进行复制。


此外,在您的CodeSandbox示例中,您将group内的state属性设置为字符串。确保使用该JSON字符串,并使用它构造一个正确的JavaScript对象,以便可以在其状态下使用它。

constructor(props) {
  super(props)
  this.setState = { group: JSON.parse(myState) }
}

这是一个可行的示例: