How to update nested state properties in React

后端 未结 26 1844
野趣味
野趣味 2020-11-21 06:35

I\'m trying to organize my state by using nested property like this:

this.state = {
   someProperty: {
      flag:true
   }
}

But updating

相关标签:
26条回答
  • 2020-11-21 07:32

    I found this to work for me, having a project form in my case where for example you have an id, and a name and I'd rather maintain state for a nested project.

    return (
      <div>
          <h2>Project Details</h2>
          <form>
            <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
            <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
          </form> 
      </div>
    )
    

    Let me know!

    0 讨论(0)
  • 2020-11-21 07:32

    Something like this might suffice,

    const isObject = (thing) => {
        if(thing && 
            typeof thing === 'object' &&
            typeof thing !== null
            && !(Array.isArray(thing))
        ){
            return true;
        }
        return false;
    }
    
    /*
      Call with an array containing the path to the property you want to access
      And the current component/redux state.
    
      For example if we want to update `hello` within the following obj
      const obj = {
         somePrimitive:false,
         someNestedObj:{
            hello:1
         }
      }
    
      we would do :
      //clone the object
      const cloned = clone(['someNestedObj','hello'],obj)
      //Set the new value
      cloned.someNestedObj.hello = 5;
    
    */
    const clone = (arr, state) => {
        let clonedObj = {...state}
        const originalObj = clonedObj;
        arr.forEach(property => {
            if(!(property in clonedObj)){
                throw new Error('State missing property')
            }
    
            if(isObject(clonedObj[property])){
                clonedObj[property] = {...originalObj[property]};
                clonedObj = clonedObj[property];
            }
        })
        return originalObj;
    }
    
    const nestedObj = {
        someProperty:true,
        someNestedObj:{
            someOtherProperty:true
        }
    }
    
    const clonedObj = clone(['someProperty'], nestedObj);
    console.log(clonedObj === nestedObj) //returns false
    console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
    console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true
    
    console.log()
    const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
    console.log(clonedObj2 === nestedObj) // returns false
    console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
    //returns true (doesn't attempt to clone because its primitive type)
    console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 
    
    0 讨论(0)
  • 2020-11-21 07:34

    Here's a variation on the first answer given in this thread which doesn't require any extra packages, libraries or special functions.

    state = {
      someProperty: {
        flag: 'string'
      }
    }
    
    handleChange = (value) => {
      const newState = {...this.state.someProperty, flag: value}
      this.setState({ someProperty: newState })
    }
    

    In order to set the state of a specific nested field, you have set the whole object. I did this by creating a variable, newState and spreading the contents of the current state into it first using the ES2015 spread operator. Then, I replaced the value of this.state.flag with the new value (since I set flag: value after I spread the current state into the object, the flag field in the current state is overridden). Then, I simply set the state of someProperty to my newState object.

    0 讨论(0)
  • 2020-11-21 07:34

    I used this solution.

    If you have a nested state like this:

       this.state = {
              formInputs:{
                friendName:{
                  value:'',
                  isValid:false,
                  errorMsg:''
                },
                friendEmail:{
                  value:'',
                  isValid:false,
                  errorMsg:''
                }
    }
    

    you can declare the handleChange function that copy current status and re-assigns it with changed values

    handleChange(el) {
        let inputName = el.target.name;
        let inputValue = el.target.value;
    
        let statusCopy = Object.assign({}, this.state);
        statusCopy.formInputs[inputName].value = inputValue;
    
        this.setState(statusCopy);
      }
    

    here the html with the event listener

    <input type="text" onChange={this.handleChange} " name="friendName" />
    
    0 讨论(0)
  • 2020-11-21 07:34

    i saw following in a book:

    this.setState(state => state.someProperty.falg = false);
    

    but i'm not sure if it's right..

    0 讨论(0)
  • 2020-11-21 07:36

    I do nested updates with a reduce search:

    Example:

    The nested variables in state:

    state = {
        coords: {
            x: 0,
            y: 0,
            z: 0
        }
    }
    

    The function:

    handleChange = nestedAttr => event => {
      const { target: { value } } = event;
      const attrs = nestedAttr.split('.');
    
      let stateVar = this.state[attrs[0]];
      if(attrs.length>1)
        attrs.reduce((a,b,index,arr)=>{
          if(index==arr.length-1)
            a[b] = value;
          else if(a[b]!=null)
            return a[b]
          else
            return a;
        },stateVar);
      else
        stateVar = value;
    
      this.setState({[attrs[0]]: stateVar})
    }
    

    Use:

    <input
    value={this.state.coords.x}
    onChange={this.handleTextChange('coords.x')}
    />
    
    0 讨论(0)
提交回复
热议问题