Lessons learned about object literals and, in React, this.setState requires an enumerable object as a parameter

No question, just some discoveries. I was reworking my Markdown Previewer to replace much of the JSX in the render() method of my Container component with a Window functional component. As part of that, I wanted to return an object to setState whose property name depended on the parameter windowType. I learned:

  1. Since property names are string literals, you can’t use string template literals to declare an object literal, like this (this code won’t work):
this.setState({
  `${windowType}Maximized`: !this.state[`${windowType}Maximized`]
});

So, if you want to use template literals to vary the name of an object property, you’re going to need to use Object.defineProperty, which led me to my second discovery:

  1. this.setState(newStateObjectToMerge) requires that the object parameters properties be enumerable for the state update to work. It doesn’t even need a value, as long as it is enumerable, React will iterate through newStateObjectToMerge and define any value-less properties as undefined in this.state. The following non-working code caused me a lot of head-scratching:
this.setState({
  Object.defineProperty({}, `${windowType}Maximized`, {value: !this.state[`${windowType}Maximized`]})
});

The correct code is:

this.setState(
  Object.defineProperty({}, `${windowType}Maximized`, {
    value: !this.state[`${windowType}Maximized`],
    enumerable: true
  })
);

For those wondering, I’ve run the experiments, and which boolean value to which you set configurable and writable doesn’t matter.