Skip to main content

Command Palette

Search for a command to run...

Building React in Vanilla JS : 103 - Adding State

Published
2 min readView as Markdown
Building React in Vanilla JS : 103 - Adding State
Y

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.

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 of currentIndex.

  • 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 of currentIndex 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).

Code Sandbox