Building React in Vanilla JS : 103 - Adding State

Table of contents

Let’s build our useState hook!
So to mimic the useState hook from React.js, the first thing that comes to mind is to define a function that takes in the initial value and returns the initial value along with a function to update that value. During this we need a data structure to store the state value. Let’s go with an array. Our _state
array. To keep a track of state variables we will have an index _stateIndex
.
So firstly we check and initialise the value in our _state
array. Then comes in the setter function which closes over the currentIndex
.
Each time we call
useState
, it captures the value ofcurrentIndex
.That value is remembered by the specific
setState
function it returns.When
setState
is later called (e.g. on button click), it uses the correct slot in the_state[]
array because it closed over the value ofcurrentIndex
when it was created.
After updating our state we need to trigger a re-render to reflect the updated values. For this let’s define a simple rerender
function.
function rerender() {
_stateIndex = 0;
render(App(), document.getElementById("app"));
}
useState
relies on the order in which it is called. At every rerender we must start from _stateIndex zero to correctly pull the related value from _state array. Thus set the _stateIndex to zero inside our rerender()
function.Now here’s our own useState
hook:
const _state = [];
let _stateIndex = 0;
const useState = (initialValue) => {
const currentIndex = _stateIndex;
if (_state[currentIndex] === undefined) {
_state[currentIndex] = initialValue;
}
const setterFuntion = (newValue) => {
_state[currentIndex] = newValue;
_stateIndex = 0;
rerender();
};
const value = _state[currentIndex];
_stateIndex++;
return [value, setterFunction];
};
Limitations
Our _state
and _stateIndex
are globally scoped. If two different components, say ComponentA
and ComponentB
, are both using useState
, their states will collide in the single _state
array. _stateIndex
will continue incrementing across all component renders, leading to incorrect state retrieval.
Next Step
The next step would be to figure out how to associate _state
and _stateIndex
with individual component instances and then how to trigger a re-render of only the affected component (the latter can be tackled once we finish with our component-scoped state).
Subscribe to my newsletter
Read articles from Yogesh Kanwade directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Yogesh Kanwade
Yogesh Kanwade
I'm Yogesh Kanwade, a final year Computer Engineering student with a deep passion for software development. I am a continuous learner, with hardworking and goal-driven mindset and strong leadership capabilities. I am actively exploring the vast possibilities of Web Development along with AWS and DevOps, fascinated by their impact on scalable and efficient web solutions.