React Hooks: Array Destructuring Fundamentals
React’s upcoming useState
hook relies on array destructuring, let’s dive in and see how that feature works.
React Hooks are currently available in the alpha release of
react@16.7.0-alpha.2
.
This is the first example on the https://reactjs.org/hooks documentation:
import { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
That const [count, setCount] = useState(0);
is the line we’re going to be talking about today. The syntax here is called “array destructuring” and it was introduced into JavaScript in the infamous (more than famous) ES6 release.
I’m a firm believer that:
The better you understand an abstraction, the more effective you will be at using it. β me, literally right when I wrote this…
So when I see syntax that I’m unfamiliar with, I like to read about it and understand how it works with the rest of the language. The problem is that it can be difficult to “Google” syntax. Seriously… Try Googling the syntax itself as if you didn’t know that it’s called “destructuring.” Pretty tough! So here’s my trick. I go to astexplorer.net and paste in the code that I don’t understand:
Cool! Babel calls that an “ArrayPattern.” So let’s go ahead and Google for that. We’ll search for “site:https://developer.mozilla.org array pattern” (that way Google only returns results for articles on MDN which is a terrific resource on learning everything there is to know about JavaScript).
Sweet, the first result takes us to “Destructuring assignment” where we can learn all about this feature (I guess you can read that instead of continuing here if you want to π ).
Often syntax like this is what we call “syntactic sugar” for other features. Here’s what wikipedia says about syntactic sugar:
In computer science, syntactic sugar is syntax within a programming language that is designed to make things easier to read or to express. It makes the language “sweeter” for human use: things can be expressed more clearly, more concisely, or in an alternative style that some may prefer.
Ok, so basically it means that there are common patterns or ways to write code in a given language, so the language makes a syntax feature to make that pattern require less code or more expressive. With this in mind, when I’m learning new syntax, I like to “de-sugar” the syntax to see what it would look like if we didn’t have that feature.
Luckily for us, we have Babel and TypeScript which can compile this newer syntax into something older browsers can support (and presumably to something we may be more familiar with). So my next step is to go to the online babel REPL and paste in the code. Here’s what the result looks like:
"use strict"; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); // const [count, setCount] = useState(0); var _useState = useState(0), _useState2 = _slicedToArray(_useState, 2), count = _useState2[0], setCount = _useState2[1];
π¬ YIKES! Hmmm… Ok, so sometimes Babel uses utilities which both make it more compliant to the specification, but also can make the code a little harder to understand. Luckily, there’s an option on the Babel Repl’s “Env Preset” called “Loose” which will simplify this output considerably:
// const [count, setCount] = useState(0); var _useState = useState(0), count = _useState[0], setCount = _useState[1];
π Phew, that’s better. Ok, so what’s going on here. Babel’s taking our one line and rather than using the Array Pattern thing, it’s assigning the return value of useState
to a variable called _useState
. Then it’s treating _useState
as an array and it assigns count
to the first item in the array and setCount
to the second one.
Let’s play around with this a little bit to explore the syntax:
Can I call the values whatever I want?
// const [whateverIWant, reallyICanChooseWhatItIsCalled] = useState(0); var _useState = useState(0), whateverIWant = _useState[0], reallyICanChooseWhatItIsCalled = _useState[1];
Can I add more elements?
// const [count, setCount, somethingElse] = useState(0); var _useState = useState(0), count = _useState[0], setCount = _useState[1], somethingElse = _useState[2];
Can I pull out fewer?
// const [count] = useState(0); var _useState = useState(0), count = _useState[0];
Can I skip one?
// const [, setCount] = useState(0); var _useState = useState(0), setCount = _useState[1];
Can I skip more?
// const [,,, wow,, neat] = useState(0); var _useState = useState(0), wow = _useState[3], neat = _useState[5];
I saw someone put a weird =
sign in there, what does that do?
// const [count = 3, setCount] = useState(0); var _useState = useState(0), _useState$ = _useState[0], count = _useState$ === undefined ? 3 : _useState$, setCount = _useState[1];
Oooh, fancy, so if the first element of the array is undefined, then we’ll set count
to 3
instead. Default values! Sweet.
Note: most of the things above you would never need to do with
useState
because we can always rely onuseState
returning an array of two elements! We’ll look at that more next.
Ok cool, so this helps us understand what’s actually going on. There’s nothing React-specific about this syntax. It’s built-into the JavaScript specification, and React’s useState
hook is leveraging it as a mechanism for an ergonomic API that allows you to get two values out of a single function call. Neat!
Ok, so what does useState
actually do then? What is it really returning? It must be returning an array for us to be doing the array destructuring like this right? Cool, let’s check that out.
One thing that’s interesting is that the implementation of useState
exists within react-dom
rather than react
. I know, that may be confusing because we import useState
from the react
package, but it actually just delegates to the current renderer (which is react-dom
in our situation here). In fact, setState
is the same way!
Another interesting thing about useState
is that the implementation in react-dom
is just a few lines:
function useState(initialState) { return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers initialState); }
π± it’s actually just a hook that’s using the useReducer
hook! Ok, but what is that basicStateReducer
thing huh?
function basicStateReducer(state, action) { return typeof action === 'function' ? action(state) : action; }
Ok, interesting, so useReducer
is actually over 100 lines of code, so let’s just look at what useReducer
returns:
return [newState, dispatch];
See! It’s an array! So when we call useState
, it returns a call to useReducer
which will return an array of two values. This allows us to do the array destructuring that we want so instead of writing:
const stateAndUpdater = useState(0); const count = stateAndUpdater[0]; const setCount = stateAndUpdater[1];
We can write:
const [count, setCount] = useState(0);
Nice!
Conclusion
I hope you found this one helpful! Even if you already are very familiar with destructing syntax, the process of learning new syntax I show above has been helpful to me as recently as Friday when I was playing around with TypeScript. Seeing syntax that I’m not familiar with and learning new things is something that I’ll never get tired of in this industry! And learning the fundamentals behind these bits of syntax will make you more effective at using them. I should mention also that there are more things you can do with destructuring and if you’re interested there’s a section about destructuring in my ES6 workshop that’s available completely free on my YouTube channel. Good luck!
Learn more about React from me:
- The Beginner’s Guide to React - Absolute fundamentals of React
- React Hooks and Suspense - A great primer on Hooks and Suspense
- Simplify React Apps with React Hooks - Let’s take some real-world class components and refactor them to function components with hooks.
- Advanced React Component Patterns - Amazing patterns to make your components more reusable, flexible, and simple all at once. (Also on Frontend Masters).
- My YouTube channel is also full of content about React that you’d probably enjoy (including workshops, talks, and livestreams).
Things to not miss:
- DevHub - TweetDeck for GitHub by Bruno Lemos. The project itself is open source and pretty impressive. It’s “a production app using React Hooks, React Native Web with a 95%+ code sharing between web and mobile, CRA, TypeScript, Yarn Workspaces and Redux”
- Modern Javascript by Example - A free (donations welcome) open source book by Ben Junya
- What I Use: Kent C. Dodds - Byteconf is starting something new by talking to their favorite folks in the software dev world to find out how they do their best work. I was the first one!
Some tweets from this last week:
I got Refactoring UI - Complete Package by @steveschoger I’ve always felt like a dev that was helpless at design, but I watched all of Steve’s RefactoringUI videos on YouTube and I’m convinced this is going to be an extremely helpful resource for me.
https://refactoringui.com/book/
I’m telling you people, this thing is nutso fast and couldn’t be easier. It actually feels like a hidden feature of Netlify it’s that good.
https://twitter.com/Netlify/status/1072202548059222017
Legit used @typescriptlang (via @babel/preset-typescript) for the first time today and so far I’m quite happy. Will give more updates when I’ve worked with it more. But so far I’m pretty optimistic. Feeling better about it than I have with Flow…
This week’s blog post is “React Hooks: Whatβs going to happen to React context?”. It’s the published version of my newsletter from 2 weeks ago. If you thought it was good, go ahead and give it some claps (πx50) and a retweet:
I just published “React Hooks: Whatβs going to happen to React context?” βοΈ
React Hooks: What’s going to happen to react context?
With the cool new stuff coming to React (Hooks/Suspense), what’s going to happen to the context api?
P.S. If you like this, make sure to subscribe, follow me on twitter, buy me lunch, support me on patreon, and share this with your friends π
π Hi! I’m Kent C. Dodds. I work at PayPal as a full stack JavaScript engineer. I represent PayPal on the TC39. I’m actively involved in the open source community. I’m the creator of TestingJavaScript.com and I’m an instructor on egghead.io and Frontend Masters. I’m also a Google Developer Expert. I’m happily married and the father of four kids. I like my family, code, JavaScript, and React.