Recreating React’s useState hook
You don’t need classes, and you don’t need the .bind() method and the confusion it creates. This is what React said with its 16.8 release. Basically, functions make it easier to improve the performance of an application. Classes are confusing to both humans and machines.
The idea of this article to get into an internal understanding of how the new hooks work. For that, I will be recreating the custom useState hook.
This is not actual code of useState hook, but just an Idea. The actual useState hook is far more complex
You can find the full code here:
So let’s start. In our App.js, we add the following code. This should simply update the name we enter in the input. The simplest component to start with:
function MyName () { const [ name, setName ] = useState(''); function handleChange (evt) {
setName(evt.target.value);
} return (
<div>
<h1>My name is: {name}</h1>
<input type="text" value={name} onChange={handleChange} />
</div>
)}
As expected, nothing works. useState is not defined. So let’s create it.
In your App.js , import ReactDOM. With the help of ReactDOM, we will re-render the component on state change. So this is how your imports should look like.
import React from 'react';
import ReactDOM from 'react-dom';Now we write our useState function step by step.
Get Nitesh Rana’s stories in your inbox
Join Medium for free to get updates from this writer.
STEP 1 — It should accept initialState as a parameter. Then we set that initialState parameter value to a local variable.
function useState(initialState) {
let value = initialState;
}STEP 2 — We can leverage the concept of JavaScript closures and create a setState function that will have access to the value variable. This function takes the state to be set as a parameter. And in the end, we re-render our component by ReactDOM.render.
function useState(initialState) {
let value = initialValue;
function setState(nextValue) {
value = nextValue;
ReactDOM.render(<MyName />, document.getElementById("root")); }
}
STEP 3 — The one last thing to add to the useState function is the return statement. useState should return the array containing the value and setState function.
function useState(initialState) {
let value = initialValue;
function setState(nextValue) {
value = nextValue;
ReactDOM.render(<MyName />, document.getElementById("root"));
}
return [value, setState];
}It still doesn’t work.
Reason:
ReactDOM.render(<MyName />, document.getElementById("root"));The moment this above render is called, the function component gets re-rendered again. The useState function is called again which resets the value to initialValue. So the state of the input is the same.
To solve this problem, we define our value variable globally. So the useState function becomes:
let value;function useState(initialState) {
if(typeof value === "undefined") value = initialState;
function setState(nextValue) {
value = nextValue;
ReactDOM.render(<MyName />, document.getElementById("root"));
}
return [value, setState];
}
With this update we see our code works, the state is updated, and the component re-rendered.
This code still has many problems, one of them being you can’t use useState multiple times as it will override. We can solve this by converting value variable to an array and keeping a counter variable.
So by re-implementing useState we have learned a couple of things:
- Hooks are simply JavaScript functions that can access React features.
- The importance of closures.
- For multiple usage, the index or counter has to be added, so the order of hooks definition matters (in our implementation).









