How to write React useState()?

Reza Samkhanian
4 min readMar 19, 2022

Hi there everyone. If you ever have worked with React, most likely you already have used useState(). You also may have read a lot about react hooks and useState(), Have you ever thought about writing it yourself? Of course not for using it, but only to understand what’s happening down there.
Today we are going to try to write useState() ourselves (or something like that). You can use React without knowing any of the things I’m going to tell and this is for the case you like to know more. You have to have a basic understanding of React and Javascript to understand this article better.

Writing stateHook()

Before we go any further, try it yourself. Probably you have used it dozen times, how are you going to write one?

Photo by Joshua Aragon on Unsplash

So let's start by specifying what do we want:

const [count , setCount] = useState(0);

We need a function that returns an array containing a variable and a function to change that variable. Don’t forget about the initial value as a parameter. We are going to call this function stateHook().

Wow. It looks like we are going a little fast. So let me explain it step by step. As I said earlier stateHook should return a variable and function, just like useState. We defined state and initial at the start. state is used to store the value. initial is a boolean which determines it is initial render or not and we need to assign initialValue to state. Then we have stateHook (why state and initial are defined out of stateHook? we will find out later). In stateHook first, We check if initial and if it’s true we assign initialValue to state. We assign initial to false obviously, we don’t need initialValue after the first render. We return state as the first element of the array. Now we get to checksetState. value is the only parameter in setState and it can be string, object, array, … and function! Yup, it can also be a function. Remember how we used useState():

So if value is a function, the returnee is the new state and if not, we just assign value to state. At the end of stateHook we return both state and setState. We left one question behind. Why state and initial are outside of stateHook? (it smells like closure here!). We have a function that has access to variables out of its scope. Variables and function together form a closure. If we put state or initial inside stateHook, we lost value of state or initial after each stateHook call or in another term every time the component is rendered. We use closure to preserve value between calls.

It seems we have completed something likeuseState() but does it really work? We are going to try it but the function we use to update value can’t make a component rerender and to fix that I cheated a little bit. Beside stateHook I used useState and in render I change a boolean to make the component rerender. We used render after setCount to see count changes.

It seems alright. count increases and decreases with each click. We defined state outside of stateHook to store value and inside stateHook we have setState to update the value. We are using closure to create a function like useState .So far so good! but there is a problem with stateHook can you guess what is it? take a moment to think.

If you add another counter you can see the problem. Both counters have the same value, no matter which decreases or increases you are clicking.

Solving problem

Although we have defined two different variables for counters they are the same and the first initial value is used for both of them. Why is that? because it does not matter how many times we use stateHook, state in stateHook is used for all. initial value is false after the first call so both of the counters are set to the first initial value. If we want to use it more than once, we need to do some modifications. To start, let’s change state to an array.

let state = [];

Now we can have more than one value in our state but if we want to use an array we need an index to get and set the right values. Each stateHook call now has to send a unique index which is value index inside state array. keep in mind stateHook indexes should be the same in each render in order to get and update the correct value. We had something like that in hooks docs:

you ensure that Hooks are called in the same order each time a component renders

Call order is kept byindex, right?

initial is removed and we check if state[index] was undefined, the initial value would be used.

This is stateHook now. Does it work?

Conclusion

Passing the correct order is really important. Also number of stateHook should be the same between renders. That’s why we can’t use stateHook in if or loop. If we use stateHook inside loop or conditional statement we may lose track of hookOrder and stateHook would return some irrelevant value.

I think the rules of hooks will make more sense now! Hooks are also working by call order but it is not handled under the hood and not by passing an index.

Thanks for reading this article. I hope it helped you to understand useState better. If you looking to read more I suggest this post. It was really instructive and it is the idea behind this article.

--

--