React Hooks Demystified
Tags: react, coding
Published: 2018-10-31 21:08:00

---
title: React Hooks Demystified
published: true
description: How much magic is there?
tags: react, coding
cover_image: https://thepracticaldev.s3.amazonaws.com/i/379mcc8sbs44bvopxcfz.jpg
---

*[Cover image by Miguel Discart, on Flickr](https://www.flickr.com/photos/miguel_discart_vrac_2/)*

At ReactConf the team around React presented a new way to implement interactive components with React called [hooks](https://reactjs.org/docs/hooks-intro.html).

They published an [RFC](https://github.com/reactjs/rfcs/blob/hooks-rfc/text/0000-react-hooks.md) so React developers could [discuss](https://github.com/reactjs/rfcs/pull/68) if this was a good idea. 

In this article, we look into **how** such a functionality could be implemented.

## What

Hooks are functions you can call inside your **functional components** to get the functionality, you would typically only get with **component classes**.

## Why

The basic idea behind hooks is to simplify React development in general, but I won't go into detail, you can read more about it from Dan Abramov, a React core developer, [here](https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889).

## Disclaimer

**Read the [docs](https://reactjs.org/docs/hooks-intro.html) first!**

This is an **ALPHA** feature of React and should not be used in production code.

In this post, we won't use React, but a few lines of code to illustrate how hooks could work.

## How

Many people think hooks are magic and go against the philosophy of React and I can't blame them. If we look at the example, it doesn't tell much about what's happening.

```javascript
import React, {useState} from "react";

function CounterButtton(props) {
  let [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
```

It uses a simple function call to `useState` and somehow manages to get us the current state **and** allows us to change it and rerender the component with the new value.

The JavaScript pros will see the culprit here: globals!

If the `useState` function doesn't meddle with call stacks to get access to our calling component function, it has to store the data globally.

And if you read Dan's article you may find this tweet:

{% twitter 1055538414538223616 %}

1. JavaScript is single threaded, if someone clears the global before calling our hook function, we will write in a fresh global and nobody can do something while our function runs as long as we only make synchronous calls.
2. React calls our **functional component** so it has control over what happens before and after that call.

## Hooks Example

Below, I’ve tried to write a simple example that illustrates how we could implement the "magic" of hooks. **This has nothing to do with the official React implementation**, but rather, it shows how the idea works.

First, we have some component definition:

```javascript
function NumberButton() {
  let [valueA, setValueA] = useState(0);
  let [valueB, setValueB] = useState(100);

  return {
    type: "button",
    props: {
      children: `A:${valueA} B:${valueB}`,
      onClick() {
        setValueA(valueA + 1);
        setValueB(valueB - 1);
      }
    }
  };
}
```

The `NumberButton` function calls the `useState` function, which has the same interface as Reacts `useState` function. 

It returns an object that is the definition of a `<button>` element with some text and a handler.

The function that renders everything into the DOM looks like this:

```javascript
function run(components, target) {
  let savedHooks = new Map();
  render();

  function render() {
    target.innerHTML = "";
    components.forEach(function(component) {
      globalHooks = savedHooks.get(component);

      if (!globalHooks) globalHooks = new Map();

      renderToDom(component, target);

      for (let [id, hookData] of globalHooks.entries()) {
        hookData.calls = 0;
        hookData.render = render;
      }

      savedHooks.set(component, globalHooks);

      globalHooks = null;
    });
  }
}

function renderToDom(component, target) {
  let { props, type } = component();

  let element = document.createElement(type);
  element.innerHTML = props.children;
  element.onclick = props.onClick;
  target.appendChild(element);
}
```

It takes an array of components and a DOM element as a render target.

It can only render flat lists of components, no nesting possible, to keep things simple. It also doesn't do any DOM diffing.

1. It creates a **local** variable `savedHooks` to store the state of all hooks.
2. It calls its local `render` function to do the actual rendering.
3. The `render` function clears the `target` DOM element and loops over the array of `components`.
4. **Here is where the magic happens:** The `globalHooks` variable is overridden right before the component function is used, either with already stored data from the last run or with a fresh `Map` object.
5. The component does its thing, like calling the `useState` function.
6. The `hookData` stored by our components call to `useState` gets a reference to the local `render` function so it can initiate a re-render and its `calls` attribute is reset.
7. The `globalHooks` data is saved **locally** for the next run.
8. The `globalHooks` is set to `null`, if there was a next component it couldn't access our data via the `globalHooks` anymore.

The actual hook function looks like this:

```javascript
let globalHooks;
function useState(defaultValue) {
  let hookData = globalHooks.get(useState);

  if (!hookData) hookData = { calls: 0, store: [] };

  if (hookData.store[hookData.calls] === undefined)
    hookData.store[hookData.calls] = defaultValue;

  let value = hookData.store[hookData.calls];

  let calls = hookData.calls;
  let setValue = function(newValue) {
    hookData.store[calls] = newValue;
    hookData.render();
  };

  hookData.calls += 1;
  globalHooks.set(useState, hookData);

  return [value, setValue];
}
```

Let's go through it step-by-step:

1. It gets a `defaultValue` that should be returned on the first call.
2. It tries to get its state from the last run from the `globalHooks` variable. This is a `Map` object set by our `run` function before our component function is called. Either it has data from the last run, or we need to create our own `hookData`.
3. The `hookData.store` array is used to store the values from last calls and the `hookData.calls` value is used to keep track of how much this function has been called by our component.
4. With `hookData.store[hookData.calls]` we can grab the last value stored by this call; if it doesn't exist we have to use the `defaultValue`.
5. The `setValue` callback is used to update our value, for example when clicking a button. It gets a reference to `calls` so it knows to which call of the `setState` function it belongs. It then uses the `hookData.render` callback, supplied by the `render` function, to initiate a re-render of all components.
6. The `hookData.calls` counter is incremented.
7. The `hookData` is stored in the `globalHooks` variable, so it can be used by the `render` function after the component function returned.

We can run the example like so:

```javascript
let target = document.getElementById("app");
run([NumberButton], target);
```

[You can find a working implementation with example components on GitHub](https://github.com/kay-is/hook-example) 

## Conclusion

While the approach I took for implementation is far away from the actual React implementation, I think it demonstrates that hooks aren't crazy dev magic, but a smart way to use JavaScript constraints, that you could implement yourself.

# My First Book

In the last months I didn't blog as much as before. That's because I wrote a book about learning the basics of React:

[![React From Zero Book Banner](https://thepracticaldev.s3.amazonaws.com/i/vx6ctxee09tog4i9c1gj.jpeg)](https://www.fullstackreact.com/react-from-zero/)

If you like understanding how React works by taking it apart, then you might like my book _React From Zero_. In the book, I dissect how React works by examining how components work, how elements are rendered, and how to create your own Virtual DOM. 

You can [download the first chapter for free here](https://www.fullstackreact.com/react-from-zero/).