Destructuring in JavaScript

25th November 2019

Destructuring allows you to assign values to variables in a quick shorthand instead of having multiple lines. I use it pretty much every day but I can't remember a time when I actually learned anything about it, it just kind of appeared in my code and I've used it ever since.

A prime example of its use in the wild is React, take this function component.

1const MyComponent: React.FC<{startCount: number}> = ({startCount}) => {
2 const [count, setCount] = useState(startCount)
4 return <button onClick={() => setCount(count + 1)}>Count ({count})</button>
Language ts

Without destructuring, it would look like this.

1const MyComponent: React.FC<{startCount: number}> = (props) => {
2 const countState = useState(props.startCount)
4 return <button onClick={() => countState[1](countState[0] + 1)}>Count ({countState[0]})</button>
Language ts

Both types of destructuing occur in this example so lets take a look at them.

Array Destructuring

1const array = [1,2,3]
3const [c1, c2, c3] = array
5c1 // 1
6c2 // 2
7c3 // 3
Language ts

With Array Destructuring you are taking the elements in the array and assigning them to variables, as a result the order of variable names is important.

This is how React's useState works and it is used here because the React developers that wrote useState have no idea what the names you want to use for the variables are.

Object Destructuring

1const author = {
2 age: 29
3 name: 'adam'
6const {age, name} = author
8age // 29
9name // adam
Language ts

With Object destructuring the names of the object's properties are important. The properties of the object become the variables that come out of the destructuring.

Lets say useState actually returned an object of {value: T, setValue: (newValue: T) => void} we would have to assign those values as:

1const {value, setValue} = useState(1)
Language ts

As you can see its not very descriptive which is why the return value from useState is an array.

You can assign different variable names to destructured properties but the process would be cumbersome if we had to do it for every useState call.

1const {value: count, setValue: setCount} = useState(1)
Language ts

useQuery and useLazyQuery

A great example of when/why you would use either return type is Apollo GraphQLs React Hooks of useQuery and useLazyQuery.

useQuery runs the query the moment the component is mounted and returns an object. This is great as you usually only have one query per component, and if you have more you should really merge them or move the code into another component. This means at a minimum you are pulling loading, error and data from useQuery.

1const {loading, error, data} = useQuery(SOME_QUERY)
Language ts

useLazyQuery on the other hand waits until it is called to run the query. To this end it returns an array the first element of which is the function to run the query and the second is the same return object as useQuery with an additional called property.

1const [getAuthors, {called, loading, error, data}] = useLazyQuery(AUTHOR_QUERY)
Language ts

I use destructring every day across all the code I write and it's become my default way of working as I'm sure it has for a lot of my fellow developers. Hopefully this article gives everyone new and old to destructuing an idea of what is going on when you use it.