0

I actually figured out how to get the result I need, but I was hoping that someone could breakdown whats going on here and why the other more straightforward paths I tried didnt work.

essentially I was needing to set some nested state at various levels using some variables(namely id of the element)

so I tried this way

 handleClick = (e) => {
    var x = e.target.id
    console.log(this.state.fields[x])
   !this.state.fields[x].disabled ? this.setState({[this.state.fields[x].disabled]:true}) : this.setState({[this.state.fields[x].disabled]:false})
}

This for whatever reason creates a state object "false" at the top level. This is weird to me because the console logs this.state.field[x] correctly.

I also tried the same but with

setState({[this.state.fields.x.disabled]:true})

and

setState({[fields.x.disabled]:true})

both of which wouldnt compile. Not to mention I cant even figure out how to easily update nested state properties...Surely there is an easy way!

Im pretty new to react so any explaination as to what the problems are here would be greatly appreciated. Ill post my solution(workaround)

James Rundle
  • 51
  • 1
  • 5
  • This is related question https://stackoverflow.com/questions/43040721/how-to-update-nested-state-properties-in-react . But it doesn't take computed properties into account. – Estus Flask Nov 10 '18 at 11:05

3 Answers3

0

created a new object and popped it back in place

i guess I would be ok with this except for the fact the fields is a pretty big dictionary as is(over 100 sub dicts) and copy and pasting that many entries sounds expensive

seems like alot of work just to flip one boolean property

handleClick = (e) => {
    var x = e.target.id

   //console.log("...",this.state.fields[x].disabled)

    if(!this.state.fields[x].disabled) {
        var cat = Object.assign({},this.state.fields)
         cat[x].disabled = true;

        this.setState({fields:cat})
    }
}
James Rundle
  • 51
  • 1
  • 5
0

fields.x accesses a property with 'x' name, it's not the same as fields[x].

Updater function should be used if updated state uses previous state. State mutation should be generally avoided because this may result in unexpected behaviour.

It likely should be:

setState(({ fields }) => ({
  fields: {
    ...fields,
    [x]: {
      ...fields[x],
      disabled: true
    }
  }
}));
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • thanks! if my structure is {fields:{x:{disabled}}} is that still the case where fields[x] and fields.x are different? – James Rundle Nov 10 '18 at 10:52
  • In the code you posted `x` is not field name but a variable. They won't be different only if `e.target.id === 'x'`. – Estus Flask Nov 10 '18 at 10:57
0
// Assuming your state is like this: 
  state = {
    fields: {
      "fieldId-1": {
        disabled: false
      },
      "fieldId-2": {
        disabled: true
      }
    }
  };

So, you are basically passing value of 'this.state.fields['fieldId-1'].disabled === false' here and actually doing this in your setState call:

   this.setState({false: false});

which definitely will create a new field in your state object at top level and same goes with rest of your cases.

If you want to update the nested property e.g 'fieldId-1', then one possible way would be by merging your changes gracefully using updater function.

    this.setState(prevState => ({
      fields: {
        ...this.state.fields,
        [x]: { disabled: !prevState.fields[x].disabled }
      }
    }));
  };

I have also created a codeSandbox demo to demonstrate my point. Hope it helps. Happy Coding :)