Mimicking React’s useState Hook with JavaScript Proxy Object
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!
You might also like
Keep reading with more notes from the journal.

JavaScript
Building “TagTamer” — A Chrome Extension with Manifest V3
Learn how to build a Chrome extension using Manifest V3 by creating TagTamer—a simple tool that highlights HTML heading tags on any webpage. This hands-on guide covers popup UI, background scripts, content scripts, and modern extension architecture.

#FutureOfWork #Productivity #TechLeadersh
The billable hour was always a workaround
In the early 1900s, coal miners across South Wales were paid by the ton. It was a reasonable arrangement. Effort and output correlated tightly enough, measurement was simple, and the variance between a fast miner and a slow one was narrow enough that the proxy held.

#Agents #Tech #Simplicity #Engineering
Not everything needs an agent
In 1931, Rube Goldberg won a Pulitzer Prize for drawings of machines that accomplished simple tasks through spectacular chains of unnecessary steps. A self-wiping napkin apparatus involving a parrot, a lit candle, a swinging pendulum, and seven other components.
