proxy.set() - Reactive Storage Proxy Set Method
Quick Start (30 seconds)
// Create a reactive storage proxy
const storage = reactiveStorage('localStorage', 'myApp');
// Set a value - automatically triggers reactivity!
storage.set('theme', 'dark');
// Watch it update in real-time
effect(() => {
const theme = storage.get('theme');
console.log('Theme changed to:', theme); // Logs: "Theme changed to: dark"
});
// Change it again - effect runs automatically
storage.set('theme', 'light'); // Logs: "Theme changed to: light"What just happened? You stored data AND got automatic reactivity - any code watching that storage key will update instantly! ✨
What is proxy.set()?
proxy.set() is a method that stores a value in browser storage (localStorage or sessionStorage) and automatically triggers reactivity.
Simply put: it's like a regular storage setter, but with superpowers. When you set a value, any reactive code watching that storage key will automatically re-run.
Think of it as a smart storage system that not only saves your data but also notifies everyone who cares about it.
Syntax
// Basic usage
proxy.set(key, value)
// With options
proxy.set(key, value, options)Parameters:
key(string) - The storage key to setvalue(any) - The value to store (will be JSON.stringify'd)options(object, optional) - Configuration optionsexpires(number) - Time in seconds until the value expires
Returns: boolean - true if successful, false if failed
Why Does This Exist?
The Problem with Regular Storage
Here's how you'd normally work with localStorage:
// Setting a value
localStorage.setItem('theme', 'dark');
// Manually updating UI
function updateTheme() {
const theme = localStorage.getItem('theme');
document.body.className = theme;
}
// You have to call updateTheme() manually every time!
localStorage.setItem('theme', 'light');
updateTheme(); // Don't forget this!
localStorage.setItem('theme', 'dark');
updateTheme(); // And this!
localStorage.setItem('theme', 'blue');
updateTheme(); // And this too!What's the Real Issue?
Set value in storage
|
v
[NOTHING HAPPENS] ❌
|
v
You must manually update UI
|
v
Easy to forget = Bugs!Problems: ❌ Manual synchronization - You must manually update everything that depends on that value
❌ Easy to forget - One missed update call = broken UI
❌ Scattered updates - Update code lives far from storage code
❌ Not scalable - More storage keys = more manual update calls
The Solution with proxy.set()
const storage = reactiveStorage('localStorage', 'myApp');
// Set up automatic UI updates
effect(() => {
const theme = storage.get('theme');
document.body.className = theme;
});
// Now just set - UI updates automatically!
storage.set('theme', 'light'); // UI updates ✨
storage.set('theme', 'dark'); // UI updates ✨
storage.set('theme', 'blue'); // UI updates ✨What Just Happened?
proxy.set('theme', 'dark')
|
v
Stores in localStorage
|
v
Triggers reactivity ✨
|
v
All effects watching 'theme' re-run
|
v
UI updates automatically! ✅Benefits: ✅ Automatic updates - Everything watching the value updates automatically
✅ Zero manual work - Set once, forget about UI updates
✅ Centralized logic - Update logic lives in effects, not scattered everywhere
✅ Scales perfectly - Add more watchers without changing storage code
Mental Model
Think of regular localStorage as a simple filing cabinet:
Regular localStorage (Filing Cabinet)
┌─────────────────────┐
│ Put file in │
│ drawer │
│ │
│ [DONE] │
│ │
│ Nobody knows │
│ you added it │
└─────────────────────┘Now think of proxy.set() as a smart filing system with notifications:
proxy.set() (Smart Filing System)
┌─────────────────────┐
│ Put file in │
│ drawer │
│ | │
│ v │
│ Ring bell 🔔 │
│ | │
│ v │
│ Alert everyone │
│ who subscribed │
│ | │
│ v │
│ They all update! │
└─────────────────────┘Key Insight: proxy.set() doesn't just store - it announces the change so everyone interested can react automatically.
How Does It Work?
Let's look under the hood at what happens when you call proxy.set():
Step-by-Step Process
1️⃣ Store the Value
storage.set('theme', 'dark');The method first stores your value in the actual browser storage:
User Data
|
v
JSON.stringify(value)
|
v
localStorage.setItem('myApp:theme', '{"value":"dark","timestamp":...}')2️⃣ Update Internal State
Internal Reactive State:
{
_version: 5, // Incremented!
_keys: Set(['theme', 'user', ...]) // Updated!
}3️⃣ Trigger Reactivity
_version changed
|
v
All effects tracking _version re-run
|
v
They call storage.get('theme')
|
v
Get new value
|
v
Update UI! ✨The Magic: Version Tracking
Here's the clever trick:
// Inside reactiveStorage()
const reactiveState = state({
_version: 0, // Changed every time set() is called
_keys: new Set() // Changed when keys are added/removed
});
// When you call proxy.get()
proxy.get = function(key) {
const _ = reactiveState._version; // ✨ Tracks dependency!
return actualStorage.getItem(key);
}
// When you call proxy.set()
proxy.set = function(key, value) {
actualStorage.setItem(key, value);
reactiveState._version++; // ✨ Triggers all watchers!
}What's happening?
- Every
get()call tracks the_versionnumber - Every
set()call increments the_versionnumber - When
_versionchanges, all effects that read it re-run - Those effects call
get()again and see the new value!
Basic Usage
Example 1: Store a Simple Value
const storage = reactiveStorage('localStorage');
// Store a string
storage.set('username', 'Alice');
// Store a number
storage.set('score', 100);
// Store a boolean
storage.set('isDarkMode', true);
// Store an object (automatically JSON.stringify'd)
storage.set('user', {
name: 'Alice',
email: 'alice@example.com'
});
// Store an array
storage.set('favorites', ['apple', 'banana', 'orange']);What's happening?
- Values are automatically serialized to JSON
- They're stored in the browser's storage
- The storage key is used as-is (no namespace in this example)
Example 2: Store with Namespace
const storage = reactiveStorage('localStorage', 'myApp');
// All keys are automatically prefixed with 'myApp:'
storage.set('theme', 'dark');
// Actually stores as: 'myApp:theme'
storage.set('language', 'en');
// Actually stores as: 'myApp:language'
console.log(localStorage.getItem('myApp:theme')); // '{"value":"dark",...}'Why use namespaces?
- Prevents conflicts with other apps/libraries
- Makes it easy to clear all your app's data
- Organizes storage keys logically
Example 3: Reactive UI Updates
const storage = reactiveStorage('localStorage', 'app');
// Store initial value
storage.set('count', 0);
// Set up automatic UI update
effect(() => {
const count = storage.get('count');
document.getElementById('display').textContent = count;
});
// Display shows: 0
// Update value - UI updates automatically!
storage.set('count', 5);
// Display shows: 5 ✨
storage.set('count', 10);
// Display shows: 10 ✨What just happened?
- We set an initial value
- We created an effect that reads the value
- Every time we set a new value, the effect re-runs
- The UI updates automatically without manual work!
Setting Values with Options
Expiring Values
You can set values that automatically expire after a certain time:
const storage = reactiveStorage('localStorage');
// This value expires in 60 seconds
storage.set('sessionToken', 'abc123', {
expires: 60 // seconds
});
// Check immediately
console.log(storage.get('sessionToken')); // 'abc123'
// Wait 61 seconds...
setTimeout(() => {
console.log(storage.get('sessionToken')); // null (expired!)
}, 61000);How expiration works:
storage.set('token', 'abc', { expires: 60 })
|
v
Stores: {
value: 'abc',
timestamp: 1704123456789,
expires: 1704123456789 + 60000 // Current time + 60 seconds
}
|
v
When you get():
|
v
Check: Now > expires?
|
+ > YES: Return null, delete from storage
|
+ > NO: Return valueReal-World Use Case: Temporary Tokens
const storage = reactiveStorage('localStorage', 'auth');
function login(username, password) {
const token = authenticateUser(username, password);
// Store token that expires in 1 hour
storage.set('authToken', token, {
expires: 3600 // 1 hour in seconds
});
}
// Later, check if user is still logged in
effect(() => {
const token = storage.get('authToken');
if (token) {
console.log('User is logged in');
} else {
console.log('Session expired - please log in');
}
});Reactive Updates
Example 1: Multiple Watchers
One storage key can trigger multiple effects:
const storage = reactiveStorage('localStorage', 'app');
// Watcher 1: Update header
effect(() => {
const theme = storage.get('theme');
document.querySelector('header').className = theme;
});
// Watcher 2: Update body
effect(() => {
const theme = storage.get('theme');
document.body.className = theme;
});
// Watcher 3: Log changes
effect(() => {
const theme = storage.get('theme');
console.log('Theme changed to:', theme);
});
// One set() triggers all three effects!
storage.set('theme', 'dark');
// Header updates ✅
// Body updates ✅
// Console logs ✅Example 2: Cross-Component Synchronization
const storage = reactiveStorage('localStorage', 'app');
// Component 1: Settings Panel
function SettingsPanel() {
effect(() => {
const fontSize = storage.get('fontSize');
document.getElementById('font-size-slider').value = fontSize;
});
document.getElementById('font-size-slider').oninput = (e) => {
storage.set('fontSize', e.target.value);
};
}
// Component 2: Article Display
function ArticleDisplay() {
effect(() => {
const fontSize = storage.get('fontSize');
document.getElementById('article').style.fontSize = fontSize + 'px';
});
}
// Change in settings panel automatically updates article!
// No manual coordination needed between componentsExample 3: Undo/Redo with Storage History
const storage = reactiveStorage('localStorage', 'editor');
const history = [];
let historyIndex = -1;
// Track changes
effect(() => {
const content = storage.get('content');
if (content !== history[historyIndex]) {
history.push(content);
historyIndex++;
}
});
function undo() {
if (historyIndex > 0) {
historyIndex--;
storage.set('content', history[historyIndex]);
}
}
function redo() {
if (historyIndex < history.length - 1) {
historyIndex++;
storage.set('content', history[historyIndex]);
}
}
// Usage
storage.set('content', 'Hello');
storage.set('content', 'Hello World');
storage.set('content', 'Hello World!');
undo(); // Back to 'Hello World'
undo(); // Back to 'Hello'
redo(); // Forward to 'Hello World'Real-World Examples
Example 1: Dark Mode Toggle
const storage = reactiveStorage('localStorage', 'theme');
// Initialize with saved preference or default
if (!storage.has('darkMode')) {
storage.set('darkMode', false);
}
// Apply theme automatically
effect(() => {
const isDark = storage.get('darkMode');
document.body.classList.toggle('dark-mode', isDark);
// Update button text
const button = document.getElementById('theme-toggle');
button.textContent = isDark ? '☀️ Light Mode' : '🌙 Dark Mode';
});
// Toggle button
document.getElementById('theme-toggle').onclick = () => {
const current = storage.get('darkMode');
storage.set('darkMode', !current);
// Everything updates automatically! ✨
};Example 2: Shopping Cart
const storage = reactiveStorage('localStorage', 'shop');
// Initialize empty cart
if (!storage.has('cart')) {
storage.set('cart', []);
}
// Update cart display automatically
effect(() => {
const cart = storage.get('cart') || [];
// Update count badge
document.getElementById('cart-count').textContent = cart.length;
// Update total
const total = cart.reduce((sum, item) => sum + item.price, 0);
document.getElementById('cart-total').textContent = `$${total.toFixed(2)}`;
});
// Add to cart
function addToCart(product) {
const cart = storage.get('cart') || [];
cart.push(product);
storage.set('cart', cart);
// UI updates automatically! ✨
}
// Remove from cart
function removeFromCart(productId) {
const cart = storage.get('cart') || [];
const filtered = cart.filter(item => item.id !== productId);
storage.set('cart', filtered);
// UI updates automatically! ✨
}Example 3: Form Auto-Save
const storage = reactiveStorage('localStorage', 'forms');
// Auto-save form data
const formState = state({
name: '',
email: '',
message: ''
});
// Save to storage on every change
effect(() => {
const data = {
name: formState.name,
email: formState.email,
message: formState.message
};
storage.set('contactForm', data);
});
// Restore form data on page load
const saved = storage.get('contactForm');
if (saved) {
formState.name = saved.name;
formState.email = saved.email;
formState.message = saved.message;
}
// Now user can refresh page and data is restored! ✨Common Patterns
Pattern 1: Initialize If Missing
const storage = reactiveStorage('localStorage', 'app');
// Safe initialization
if (!storage.has('settings')) {
storage.set('settings', {
theme: 'light',
language: 'en',
notifications: true
});
}Pattern 2: Update Object Properties
const storage = reactiveStorage('localStorage', 'app');
// Get current settings
const settings = storage.get('settings') || {};
// Update one property
settings.theme = 'dark';
// Save back
storage.set('settings', settings);Pattern 3: Batch Updates
const storage = reactiveStorage('localStorage', 'app');
batch(() => {
storage.set('firstName', 'John');
storage.set('lastName', 'Doe');
storage.set('email', 'john@example.com');
});
// All three updates trigger effects only once!Pattern 4: Conditional Storage
const storage = reactiveStorage('localStorage', 'app');
function saveUserPreference(key, value) {
// Only save if user is logged in
const isLoggedIn = storage.get('isLoggedIn');
if (isLoggedIn) {
storage.set(key, value);
} else {
console.log('Not logged in - preference not saved');
}
}Pattern 5: Validation Before Storage
const storage = reactiveStorage('localStorage', 'app');
function setUserAge(age) {
// Validate before storing
if (typeof age !== 'number') {
console.error('Age must be a number');
return false;
}
if (age < 0 || age > 150) {
console.error('Age must be between 0 and 150');
return false;
}
return storage.set('userAge', age);
}Summary
What is proxy.set()?
A method that stores values in browser storage AND triggers automatic reactivity - any code watching that storage key will update instantly.
Why use it?
- ✅ Automatic UI updates when storage changes
- ✅ No manual synchronization needed
- ✅ Multiple components can watch the same storage key
- ✅ Built-in expiration support for temporary data
- ✅ Namespace support to organize keys
Key Takeaway:
Regular Storage proxy.set()
| |
Set value Set value
| |
[DONE] Trigger all watchers
|
Everything updates! ✨One-Line Rule: proxy.set() = localStorage + automatic notifications to all interested parties.
When to use proxy.set():
- Storing user preferences that affect UI
- Shopping carts, wishlists, or other user data
- Form auto-save functionality
- Theme/language settings
- Any data that needs to stay synced across multiple UI components
Remember: Set once, update everywhere automatically! 🎉