反应setState的深层嵌套值 [英] React setState of for deeply nested value

查看:68
本文介绍了反应setState的深层嵌套值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I’ve got a very deeply nested object in my React state. The aim is to change a value from a child node. The path to what node should be updated is already solved, and I use helper variables to access this path within my setState.

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

Anyway, I really struggle to do setState within this nested beast. I abstracted this problem in a codepen: https://codesandbox.io/s/dazzling-villani-ddci9

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

In this example I want to change the child’s changed property of the child having the id def1234.

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

As mentioned the path is given: Fixed Path values: Members, skills and variable Path values: Unique Key 1 (coming from const currentGroupKey and both Array position in the data coming from const path

这是我的状态对象:

constructor(props) {
  super(props);
  this.state = { 
    group:
    {
      "Unique Key 1": {
        "Members": [
          {
            "name": "Jack",
            "id": "1234",
            "skills": [
              {
                "name": "programming",
                "id": "13371234",
                "changed": "2019-08-28T19:25:46+02:00"
              },
              {
                "name": "writing",
                "id": "abc1234",
                "changed": "2019-08-28T19:25:46+02:00"
              }
            ]
          },
          {
            "name": "Black",
            "id": "5678",
            "skills": [
              {
                "name": "programming",
                "id": "14771234",
                "changed": "2019-08-28T19:25:46+02:00"
              },
              {
                "name": "writing",
                "id": "def1234",
                "changed": "2019-08-28T19:25:46+02:00"
              }
            ]
          }
        ]
      }
    }
  };
}

handleClick = () => {
  const currentGroupKey = 'Unique Key 1';
  const path = [1, 1];
  // full path: [currentGroupKey, 'Members', path[0], 'skills', path[1]]
  // result in: { name: "writing", id: "def1234", changed: "2019-08-28T19:25:46+02:00" }

  // so far my approach (not working) also its objects only should be [] for arrays
  this.setState(prevState => ({
    group: {
      ...prevState.group,
      [currentGroupKey]: {
        ...prevState.group[currentGroupKey],
        Members: {
          ...prevState.group[currentGroupKey].Members,
          [path[0]]: {
            ...prevState.group[currentGroupKey].Members[path[0]],
            skills: {
              ...prevState.group[currentGroupKey].Members[path[0]].skills,
              [path[1]]: {
                ...prevState.group[currentGroupKey].Members[path[0]].skills[
                  path[1]
                ],
                changed: 'just now',
              },
            },
          },
        },
      },
    },
  }));
};

render() {
  return (
    <div>
      <p>{this.state.group}</p>
      <button onClick={this.handleClick}>Change Time</button>
    </div>
  );
}

我将不胜感激.我已经挣扎了两天:/

I would appreciate any help. I’m in struggle for 2 days already :/

推荐答案

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

Before using new dependencies and having to learn them you could write a helper function to deal with updating deeply nested values.

我使用以下助手:

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

这篇关于反应setState的深层嵌套值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆