How React Works Under the Hood: Building a Tiny React Clone with Vanilla JS

How React Works Under the Hood: Building a Tiny React Clone with Vanilla JS

·

4 min read

Ever wondered what it would be like to build a React app without React? 🧐 Well, brace yourself because we’re about to dive into the chaotic yet enlightening world of manual state management and DOM updates with vanilla JavaScript. By the end of this, you'll not only understand React better but also appreciate why you don't write apps like this anymore. 😅


The Problem: Why React Exists

Picture this: You’ve got a simple button that displays a count. Every time you click it, the count increments. Sounds easy, right? But here’s the twist—you can’t use React, Vue, or any of those fancy frameworks. Just plain old JavaScript.

Now, without React’s magic, you’ll quickly realize that keeping the UI in sync with the state is like juggling chainsaws while riding a unicycle. Let me show you what I mean.


The Manual Approach: Vanilla JS FTW đŸŒ±

Here’s the code that simulates React’s state management and rendering process manually:

let state = {
    count: 0,
};

function onButtonClick() {
    state.count++;
    console.log("onButtonClick is called");
    buttonComponentRerender();
}

function buttonComponentRerender() {
    const root = document.getElementById("root");
    root.innerHTML = ""; // Clear the root element
    const component = buttonComponent(state.count);
    root.appendChild(component); // Append the updated component
}

function buttonComponent(count) {
    const btn = document.createElement("button");
    btn.addEventListener("click", onButtonClick); // Attach the click handler properly
    btn.innerHTML = "count " + count;
    console.log("button is created");
    return btn;
}

// Initial render
buttonComponentRerender();

Breaking It Down: What’s Happening Here?

1. State Management

The state object holds our application’s data—in this case, just a count property. Every time you click the button, state.count++ updates the count. Pretty basic, right?

2. Event Handling

The onButtonClick function handles the button’s click event. After updating the state, it triggers a rerender by calling buttonComponentRerender().

3. Manual DOM Updates

buttonComponentRerender():

  • Clears out the root element using root.innerHTML = "".

  • Creates a new button by calling buttonComponent().

  • Appends the updated button to the DOM.

4. Dynamic Component Creation

buttonComponent(count) generates a new button element with the updated count and attaches the click event listener. Every click rebuilds the button from scratch.


The Pain Points: Why This Sucks 😭

  1. Performance Nightmare: We’re nuking the entire DOM and rebuilding it on every click. Imagine doing this for a complex UI—your browser might just give up on life.

  2. Messy Event Handling: Reattaching event listeners on every render is tedious and error-prone.

  3. No Reusability: Every component is manually created, so scaling this approach is like writing essays by carving them on stone tablets.


The React Way: Why React Is a Blessing

React simplifies this chaos by:

  1. Virtual DOM: Instead of nuking the entire DOM, React calculates the minimum changes needed and updates the DOM efficiently.

  2. Declarative UI: With JSX, you describe what the UI should look like, and React handles the how.

  3. Reusable Components: Components can be reused like LEGO bricks, making your code DRY and scalable.

Here’s what our button component would look like in React:

import React, { useState } from 'react';

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

    return (
        <button onClick={() => setCount(count + 1)}>
            count {count}
        </button>
    );
}

export default ButtonComponent;

What We Learned: Manual vs React

Building this tiny React clone taught us a few things:

  • State and UI are closely linked: Any state change requires a UI update.

  • Frameworks save time and headaches: React abstracts away the nitty-gritty of manual DOM manipulation.

  • Appreciate the tools you have: Writing apps like this manually is a pain—React’s declarative model is a lifesaver.


Final Thoughts: The React Love Letter 🌟

If you’ve ever taken React for granted, try building something manually with vanilla JS. It’ll make you want to hug React’s Virtual DOM and say, “I’ll never doubt you again.”

Now, go forth and write some React apps—and the next time someone asks why you’re using React, you’ll have the perfect answer.

P.S. If this blog gave you flashbacks to early 2010s web dev struggles, you’re not alone. Drop a comment or meme below to share the pain! đŸ€Ł

Did you find this article valuable?

Support Abhishek Raut by becoming a sponsor. Any amount is appreciated!

Â