Understanding this.setState({ [name]: value})

What is going on here?

When I first started learning JavaScript, I was confused about exactly what line 3 above what trying to accomplish. I knew that changing an input field created an event object and that line 2 was destructing that event object into two separate variables, name and value, but I had no clue what line 3 was accomplishing. How could this.setState take a key as an array?

Specifically — what was this piece of code doing:

{[name]: value}

Understanding {[name]: value}

To break down what is happening, let’s look at an example.

const key = 'Mickey Mouse'
const value = 'Happy'
const disneyCharacter = {
[key]: value,
}
console.log(disneyCharacter)

When I console.log(disneyCharacter) I get back the following:

{Mickey Mouse: 'Happy'}

In Javascript, when you create an object literal {} and you wrap the object’s key in array brackets [key] you can dynamically set that key.

So in our example when I created the disneyCharacter object, I dynamically set the object’s key in the disneyCharacter object to Mickey Mouse.

Why?

const disneyCharacter = {
[key]: value,
}

Because I declared the variable const key = 'Mickey Mouse' in the first line of my example, the key of object disneyCharacter became Mickey Mouse. Similarly because I declared that variable const value = 'Happy' in the second line of my example, the value of object disneyCharacter became Happy.

Of course the variable names (const key and const value) do not have to be key and value. These were used to better illustrate dynamically setting keys and their respective values in JavaScript objects.

We could have easily done this.

const characterName = 'Mickey Mouse'
const mood = 'Happy'
const disneyCharacter = {
[characterName]: mood,
}
console.log(disneyCharacter)

Which would return the same key and value as above:

{Mickey Mouse: 'Happy'}

Like my above example, I dynamically set the object’s key in the disneyCharacter object to Mickey Mouse because I declared that variable const characterName = 'Mickey Mouse' in the first line of my example and then interpolated that variable into my JavaScript object with the [characterName] syntax.

Why can’t I do this (see below)

const characterName = 'Mickey Mouse'
const mood = 'Happy'
const disneyCharacter = {
`${characterName}`: mood,
}

ES6 introduced the concept of template literals (also called template strings). This isn’t an article about template literals, but briefly template literals allow you concatenate strings without having to use the + operator.

Here is an example of using the + operator.

var parkName = 'Disneyland'
'I love ' + parkName
returns ---> "I love Disneyland"

Here is an example of using the template literals.

var parkName = 'Disneyland'
`I love ${parkName}`
returns ---> "I love Disneyland"

Template literals use back-ticks and ${} to dynamically set variables in a JavaScript string.

So knowing a little about template literals, can we do the following?

const disneyCharacter = {
[characterName]: mood,
}
IS ABOVE THE SAME AS BELOW?
const disneyCharacter = {
`${characterName}`: mood,
}

Unfortunately no, you can’t set the key of an object with just a template literal.

But you can do this (see below)

const characterName = 'Mickey'
const mood = 'happy'
const disneyCharacterss = {
[`${characterName}`]: mood,
}
returns --> {Mickey: "Happy"}

But why would you do this? [`${characterName}`]

Let’s say you needed to modify the key on the object with some specific logic. For example, let’s say I have a photograph object containing the key/value pair sky-color: blue. But I also need another key/value pair detailing the inverse color of the sky aka. sky-color-inverse: orange. A template literal setting a dynamic object key might come in handy. Let’s look below.

function inverseSkyColor(value) {
returns 'orange'
}
const key = 'sky-color'
const value = "blue'
const photograph = {
[key]: value,
[`${key}-inverse`]: inverseSkyColor(value), // Calls function
}
returns ---> 
{sky-color: "blue", sky-color-inverse: "orange"}

By dynamically setting keys in object literals and using template literals you can quickly build dynamic JavaScript objects with little code.

So how is this.setState({ [name]: value}) useful in React?

Let’s look at this basic React form:

This form is fine. But it could use refactoring especially in regards to the handleChange associated with the input fields, first name and age. If this form were to grow to have several more fields, writing a handleChange function for every input field would become exhausting.

handleFirstNameChange, handleAgeChange, handleLocationChange, handleEyeColorChange, handleHeightChange, handleLastNameChange...

Luckily for us there is a solution to this problem. Instead of creating a explicit handleChange function for every type of input change, we create a generic handleChange function that looks at the name attribute (name=) on each input type and dynamically sets the component’s state based on the input field’s name attribute (name=) and the value associated with it.

Here is an example of same form above refactored using a generic handleChange function: this.setState({ [name]: value] ).

The main point is that we no longer have any individual handleChange function for each type of input change. We now have ONE handleChange function that handles each type of input and its respective change event.

The Dynamic onChange Function

Let’s break down what is happening here.

In line 1:

We are passing in the event object created by a change in either first name or age input field.

In line 2:

We are destructing that event. Destructing is a fancy JavaScript technique that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. In our case we are breaking out the event object into a target variable and then further breaking that target variable into two separate variables, name and value.

In our case the name variable is the name attribute (name=) of the input field. The value variable is the actual value the user entered into that input field.

To clarify let’s console.log the destructed variable, name for both input fields, first name and age.

For example --> 
<input 
name=”firstName”
type=”text”
value={this.state.firstName}
onChange={this.handleChange} />
console.log(name, 'ATTRIBUTE NAME') -> firstName,'ATTRIBUTE NAME'
<input 
name=”age”
type=”number”
value={this.state.age}
onChange={this.handleChange} />
console.log(name, 'ATTRIBUTE NAME') -> age,'ATTRIBUTE NAME'

In line 3:

Because we destructed the event object and now know the name of the input field and the value associated with it, we can dynamically set the state with one simple line.

this.setState({ [name]: value} )

Changing any input field in the form will update the component’s state to reflect that input fields’ attribute name and value.

For example filling in the input field firstName to Mickey Mouse will automatically set the components state to {firstName: Mickey}.

Conclusion

this.setState({ [name]: value} ) is powerful because it allows you handle your input field change events in one simple line, instead of having to write out a bunch of handleChange functions for each different input field. Your code becomes more concise and easier to read!

Keep Chugging People!

Want to Learn More About Basic JavaScript?

Read my series here!