Tensor Labs
Mimicking React’s useState Hook with JavaScript Proxy Object

Mimicking React’s useState Hook with JavaScript Proxy Object

Discover More

Learn how to recreate React’s useState-style reactivity in vanilla JavaScript using the Proxy object. This hands-on guide shows how to auto-update the UI, manage state changes, and add validations—without any frameworks.

Introduction

Ever wished you could bring the reactivity of React’s useState to your vanilla JavaScript projects? You’re in luck! With JavaScript’s Proxy object! 🎉 Today, we're diving into how this incredible feature can help you mimic React's reactivity. But first, let's embark on a little storytelling journey

A Tale of Manual Updates

Let me share a story from my own experience. I was working on a project where I needed to update values on the screen whenever the underlying data changed. It was a challenge because I had to manually write code to update the display each time the data changed. It felt like a real hassle and made the process more complicated.

Wish I had known about the Proxy object back then! We can use it to automatically trigger UI updates whenever the data changes, much like React’s state. 🌟 Let’s break down how we can achieve this with three simple code snippets.

Part 1: Basic Proxy Setup

First, let’s set up our basic Proxy that logs changes whenever the object’s properties are updated. Here’s how we start:

document.addEventListener('DOMContentLoaded', () => {
  const target = { count: 0 };

  const handler = {
    set: function (obj, prop, value) {
      if (prop === 'count') {
        console.log(

Setting count to ${value}

);
      }
      obj[prop] = value;
      return true;
    }
  };

  const proxy = new Proxy(target, handler);
});

In this code, we’re defining a Proxy with a handler that listens for changes to the count property. Whenever count is updated, a message is logged to the console. Simple, but super effective for understanding how Proxy works!

Part 2: Connecting Proxy to the UI

Now, let’s take it up a notch and connect our Proxy to update the UI. Here’s how we do it:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Counter</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="counter-container">
    <div class="count-display">Count: <span id="count">0</span></div>
    <div class="button-container">
      <button id="subtract-btn" class="btn">-</button>
      <button id="add-btn" class="btn">+</button>
    </div>
  </div>
  <script src="script.js"></script>
</body>
</html>
document.addEventListener('DOMContentLoaded', () => {
  const target = { count: 0 };

  const handler = {
    set: function (obj, prop, value) {
      if (prop === 'count') {
        console.log(

Setting count to ${value}

);
        const countElement = document.getElementById('count');
        countElement.innerText = value;
      }
      obj[prop] = value;
      return true;
    }
  };

  const proxy = new Proxy(target, handler);

  document.getElementById('add-btn').addEventListener('click', () => {
    proxy.count += 1;
  });

  document.getElementById('subtract-btn').addEventListener('click', () => {
    proxy.count -= 1;
  });

In this setup, the Proxy updates the UI element when the count property changes.

Part 3: Adding Validations with Toast Notifications

Finally, let’s add a toast notification to handle validations and prevent negative counts. Here’s the updated code snippet that includes a toast for user feedback:

//lets update the handler for the toast function
const handler = {
    set: function (obj, prop, value) {
      if (prop === 'count') {
        if (value < 0) {
          showToast('Negative numbers aren\'t allowed');
          return false; // Prevent setting the value if negative
        }
        console.log(

Setting count to ${value}

);
        const countElement = document.getElementById('count');
        countElement.innerText = value;
        countElement.classList.add('change');
        setTimeout(() => {
          countElement.classList.remove('change');
        }, 300);
      }
      obj[prop] = value;
      return true;
    }
  };

function showToast(message) {
  const toast = document.getElementById('toast');
  toast.innerText = message;
  toast.classList.add('show');
  setTimeout(() => {
    toast.classList.remove('show');
  }, 3000); // Hide toast after 3 seconds
}

This little function displays a toast message whenever an invalid action (like going below zero) occurs.

Conclusion

So, the next time you’re building a web app and want seamless reactivity, consider using the Proxy object. It’s a game-changer that brings both elegance and simplicity to your JavaScript projects. Happy coding!

Mimicking React’s useState Hook with JavaScript Proxy Object | Tensor Labs