Tushar Tiwari
Tushar

Tushar

Behind the Scenes of React useState Hook.

Demystifying React's useState by Rebuilding the Hook from scratch.

Behind the Scenes of React useState Hook.

Introduction

So every React developer must have used React's useState Hook someday, but if you haven't here's a little intro -
In React, the useState hook is used inside a Functional Component to declare, read and update state variable.

Syntax -

const [value, setValue] = useState(defaultValue);

Example -

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>The counter example</h1>
      <button onClick={() => setCount(count - 1)}>-</button>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

And it Works! ✨✨✨

The simplicity of this hook by simply letting us create a state by calling a function made me wonder how React does all of this magic.

Let's understand how React handles useState by:

Rebuilding the useState hook -

What we've observed is useState is a function that takes value and returns an array of two elememts including a variable having defaultValue of our state and a function to update the state something like this:

const useState = (value) => {
  function setValue() {
    // some logic here...
  }
  const state = [value, setValue];
  return state;
}

Let's figure out what setValue do?

when we call setValue() it updates our state's value and most importantly makes the application re-renders,
so that's what we are going to do here too.

const rootEl = document.getElementById("root");

function setValue(newValue) {    
    value = newValue;     // 1. update value
    renderReact();        // 2. rerender React
}

function renderReact() {
    ReactDOM.render(<App/>,rootEl);
}

And yes, we did both things but still, the count is not getting updated in the browser. Why so?

I smashed my head like a hundred times and finds out It's because every time we call setValue using Btn Click our useState expects it as a new hook we just want to create and declare a new state for us from defaultValues and returns that.

To better understand this, try pressing + below and see the console.
You will notice that it's giving the same default state on every Btn click.

To solve this, we need to do three things -

  1. Declare the state outside the useState function so that it doesn't get garbage collected when the function completes its execution.
  2. Add up a condition inside useState that says don't create a new state if there's already a state.
  3. Instead of assigning the newValue to value, assign it to state[0] because we know that state has already been initialized.

Let's do it.

...
let state = [];          // 1st condition
const useState = (value) => {
  if(state.length)       // 2nd condition
    return state;

  function setValue(newValue) {
    state[0] = newValue;  // 3rd condition
    renderReact();
  }
  ...
}

And finally, after a lot of tweaking the code, it is finally working.

PS: This code only works for single useState per Component, If you want to use multiple states check out this awesome talk by Ryan. I assure you it's worth the time.

This definitely is just a broad picture of what useState does. It handles a lot of other things like maintaining hooks Array, memory cells etc.

Conclusion -

We are at the very end of this article and now you may think that I know all about hooks, but really it is just the tip of the iceberg. Understanding the code which we write is definitely an awesome idea. So, I recommend you don't just stop here and check out some of the resources below:

Resources -

That's it for this article, I hope you liked this. Please share your feedback and questions (if any) in replies!

 
Share this