State Management
Built-in utilities for complex state, undo/redo history, and persistence.
While fine-grained signals are perfect for isolated values, applications often require structured state, time-travel debugging, and local storage persistence. Ripple.js provides these as zero-dependency utility functions.
Reactive Stores
A store is a deeply reactive proxy around a standard JavaScript object or array. Instead of creating individual signals for every property, you can wrap an entire object.
import { store, effect } from 'ripple-reactive';
const user = store({
name: 'Aditya',
preferences: {
theme: 'dark',
notifications: true
}
});
effect(() => {
// This effect only tracks `user.preferences.theme`
console.log(`Theme switched to: ${user.preferences.theme}`);
});
// Triggers the effect
user.preferences.theme = 'light';
// Does NOT trigger the effect (name wasn't read inside the effect)
user.name = 'ADITYA SING';Stores use JavaScript Proxies under the hood to intercept property access. This means nested objects and arrays are automatically made reactive as you access them.
Time-Travel (Undo/Redo)
Ripple.js includes a built-in createHistory wrapper that attaches a time-travel timeline to any signal or store. This is exceptionally useful for canvas editors, rich text interfaces, or complex forms.
import { signal } from 'ripple-reactive';
import { createHistory } from 'ripple-reactive/history';
const documentText = signal('');
const { undo, redo, canUndo, canRedo, history } = createHistory(documentText, {
maxDepth: 50 // Limit the stack size to prevent memory leaks
});
// User types
documentText.value = 'Hello';
documentText.value = 'Hello World';
console.log(documentText.value); // 'Hello World'
if (canUndo()) {
undo();
console.log(documentText.value); // 'Hello'
}
redo();
console.log(documentText.value); // 'Hello World'Persistence
The persist utility automatically syncs a signal or store to the browser's localStorage or sessionStorage. It handles JSON serialization and deserialization automatically.
import { signal } from 'ripple-reactive';
import { persist } from 'ripple-reactive/persistence';
// Initializes with the value from localStorage if it exists,
// otherwise defaults to 'dark'.
const theme = persist(signal('dark'), {
key: 'ripple-app-theme',
storage: window.localStorage
});
// Automatically saved to localStorage instantly
theme.value = 'light';Combining Utilities
Because Ripple.js utilities are highly composable, you can wrap a persistent store in a history tracker to create an undo-able state that survives page reloads.
const settings = persist(store({ volume: 50, brightness: 80 }), {
key: 'app-settings',
storage: window.localStorage
});
const settingsHistory = createHistory(settings);Once you save this, the next logical step is to create the framework adapters guide inside the content/docs/frameworks/index.mdx file.