动态扩展setState在三元运算符扩展上不起作用

时间:2019-03-08 15:33:56

标签: javascript reactjs

我有这样的嵌套状态:

this.state = {
  fields: {
    subject: '',
    from: {
      name: '',
    },
  },
};

onChange函数中,我正在处理对这些嵌套值的更新。

我正在尝试使用点表示法为深层嵌套动态分布setState()

例如,使用数组:const tree = ['fields','subject'],我可以使用以下命令更新subject状态值:

this.setState(prevState => ({
  [tree[0]]: {
    ...prevState[tree[0]],
    ...(tree[2] ? {
      ...prevState[tree[1]],
      [tree[2]]: value
    } 
    : { [tree[1]]: value })
  },
}));

由于三元运算符以{ [tree[1]]: value }结尾

但是当我的tree数组是:const tree = ['fields','from','name']时,fields.from.name的状态值没有改变,它应该解析为三元运算符的第一部分:

{
  ...prevState[tree[1]],
  [tree[2]]: value
}

我想念什么吗?

2 个答案:

答案 0 :(得分:3)

当我感觉自己正在重新发明轮子时,我已经越来越喜欢使用库来实现这些功能。 lodash提供了set函数(它还支持字符串路径):

_.set(object, path, value)

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4

_.set(object, ['x', '0', 'y', 'z'], 5);
console.log(object.x[0].y.z);
// => 5

您还希望使用_.cloneDeep(value),因为_.set会改变对象。

this.state = {
  fields: {
    subject: '',
    from: { name: '' },
  },
};


const tree = ['fields', 'from', 'name']; // or 'fields.from.name'
this.setState(prevState => {
  const prevState_ = _.cloneDeep(prevState);
  return _.set(prevState_, tree, value);
});

答案 1 :(得分:2)

您将需要一个循环。例如:

function update(prevState, tree, value) {
    const newState = {};
    let obj = newState;
    for (let i = 0; i < tree.length; ++i) {
        const name = tree[i];
        if (i === tree.length - 1) {
          obj[name] = value;
        } else {
          obj = obj[name] = {...prevState[name]};
        }
    }
    return newState;
}

实时示例:

this.state = {
  fields: {
    subject: '',
    from: {
      name: '',
    },
  },
};

function update(prevState, tree, value) {
    const newState = {};
    let obj = newState;
    let prev = prevState;
    for (let i = 0; i < tree.length; ++i) {
        const name = tree[i];
        if (i === tree.length - 1) {
          obj[name] = value;
        } else {
          const nextPrev = prev[name];
          obj = obj[name] = {...nextPrev};
          prev = nextPrev;
        }
    }
    return newState;
}

const tree = ['fields','from','name']
const value = "updated";
console.log(update(this.state, tree, value));

我敢肯定,可以调用Array#reduce(因为可以执行任何数组操作),但是它不会给您带来任何好处。