最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - update nested object with (ES6) computed property name - Stack Overflow

programmeradmin1浏览0评论

In my case, I'm using React.js and I would like to dynamically update the values in the deployOptions object.

For example -

initial state looks like:

getInitialState() {
    return {
      deployOptions: {
        config: null,
        action: 'deploy',
        env: 'qa'
      }
    }
  }

Obviously this is not correct - but this is what I'm trying to achieve

configOptionChange(option) {

    // option -> { key: 'env', value: 'prod' }

    this.setState({
      [deployOptions.option.key]: option.value
    });
  }

so that my state would then be

{
    deployOptions: {
      config: null,
      action: 'deploy',
      env: 'prod' // only this changes
    }
}

In my case, I'm using React.js and I would like to dynamically update the values in the deployOptions object.

For example -

initial state looks like:

getInitialState() {
    return {
      deployOptions: {
        config: null,
        action: 'deploy',
        env: 'qa'
      }
    }
  }

Obviously this is not correct - but this is what I'm trying to achieve

configOptionChange(option) {

    // option -> { key: 'env', value: 'prod' }

    this.setState({
      [deployOptions.option.key]: option.value
    });
  }

so that my state would then be

{
    deployOptions: {
      config: null,
      action: 'deploy',
      env: 'prod' // only this changes
    }
}
Share Improve this question edited Dec 3, 2015 at 17:31 Ben asked Dec 3, 2015 at 17:05 BenBen 5,3619 gold badges38 silver badges45 bronze badges
Add a comment  | 

5 Answers 5

Reset to default 14

It's not especially pretty, but I think this is the best you can do with ES6:

configOptionChange({ key, value }) {
  this.setState({
    ...this.state,
    deployOptions: {
      ...this.state.deployOptions,
      [key]: value
    }
  });
}

It's basically equivalent to your own Object.assign solution but using the ES6 spread (...) operator (and argument destructuring for good measure).

Here's a second option that isn't as clever but feels a little cleaner to me:

configOptionChange({ key, value }) {
  const { deployOptions: prevDeployOptions } = this.state;
  const deployOptions = { ...prevDeployOptions, [key]: value };
  this.setState({ ...this.state, deployOptions });
}

Just like these are nested objects, you can nest ES6 Computed Property Name like this:

[yourNestedObject]: {...yourNestedObject, [nestedObjectProperty]: value}

Here is an example function that will update an object's properties and the properties of nested objects. Where prop is the property to change, value is the value to assign, and propObj is the name of your nested object. I used useState hook for this.

const [obj, setObj] = useState({
    prop1: '',
    prop2: '',
    nestedObj: {
        prop1: '',
        prop2: ''
    }
});
const updateObj = (prop, value, propObj=false) => {
    if (propObj) {
        setObj({...obj, [propObj]: {...obj[propObj], [prop]: value}})
    } else {
        setObj({...obj, [prop]: value})
    }
}

I think this might do the trick - but if anyone has a better solution?

configOptionChange(option) {

    this.setState({
      deployOptions: Object.assign({}, this.state.deployOptions, {[option.key]: option.val})
    });

  }

I'm using reduce to update the state of a component from a passed string of path properties:

handleChangeNested(event) {
    const target = event.target; //an <input /> tag
    let newState = { ...this.state };
    let valuePath = target.name.split('.'); //the input's name is the the keys of the state object like 'group1.input1'

    // Move down in the state object until we get to the 'bottom' property and change its value
    // If the object does not have the properties we create them on the fly
    valuePath.reduce((acc, key, index, path) => {
        if (index === path.length - 1) {
            acc[key] = target.value;
        }
    
        acc[key] = acc[key] || {};
        return acc[key];
    }, newState);

    this.setState(newState);
}

The best solution I know would be to use "immutable" library.

configOptionChange(option) {       
  // option -> { key: 'env', value: 'prod' }

  this.setState(state => setIn(state, ['deployOptions', option.key], option.value));
}
发布评论

评论列表(0)

  1. 暂无评论