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:
- 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:
-
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 throughnewStateObjectToMerge
and define any value-less properties asundefined
inthis.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.