Persistent Storage
The Persistent Storage functionality is provided through the persistent
function, which creates reactive objects that automatically synchronize with localStorage
. This allows you to work with persistent data as if it were regular JavaScript objects while having changes automatically saved.
Two Way Binding
Anchor stores the data in localStorage
and automatically syncs
it with the reactive object. When the engine detect a change made from another browser tab, the object will be updated.
API
persistent()
Creates a reactive persistent object that syncs with localStorage.
type persistent = <T, S>(name: string, init: T, options?: StateOptions<S>) => T;
Parameters:
name
- The unique name for the persistent storage instanceinit
- The initial data to populate the storage withoptions
- Optional configuration options for the storage
Returns: A reactive object that persists data to localStorage
Naming Convention
The name
parameter supports versioning through a special syntax:
// Simple name
const settings = persistent('user-settings', { theme: 'light' });
// With version
const settings = persistent('user-settings@1.0.0', { theme: 'light' });
// With version and previous version for migration
const settings = persistent('user-settings@2.0.0:1.0.0', { theme: 'light' });
When a previous version is specified, the storage system will automatically clean up the old version data.
persistent.leave()
Disconnects a reactive persistent object from localStorage synchronization.
type leave = <T>(state: T) => void;
Parameters:
state
- The reactive object to stop syncing with localStorage
Usage Examples
Basic Usage
import { persistent } from '@anchorlib/storage';
// Create a persistent storage for user preferences
const userPrefs = persistent('user-preferences', {
theme: 'light',
language: 'en',
notifications: true,
});
// Access and modify data as regular object properties
console.log(userPrefs.theme); // 'light'
userPrefs.theme = 'dark';
userPrefs.language = 'es';
// Changes are automatically persisted to localStorage
// No need for manual save operations
Working with Complex Data
import { persistent } from '@anchorlib/storage';
// Store complex nested objects
const userProfile = persistent('user-profile', {
personal: {
name: 'John Doe',
age: 30,
email: 'john@example.com',
},
preferences: {
theme: 'dark',
fontSize: 14,
},
history: [],
});
// Modify nested properties
userProfile.personal.name = 'Jane Doe';
userProfile.preferences.fontSize = 16;
userProfile.history.push({ action: 'login', timestamp: new Date() });
// All changes are automatically persisted
Using with Anchor Options
import { persistent } from '@anchorlib/storage';
// Create persistent storage with Anchor options
const todos = persistent(
'todos',
[
{ id: 1, text: 'Learn Anchor', done: false },
{ id: 2, text: 'Build an app', done: false },
],
{
// Enable immutability
immutable: true,
// Disable observation if only derivation is needed
observable: false,
}
);
// Work with the data
todos.push({ id: 3, text: 'Profit', done: false });
Managing Storage Lifecycle
import { persistent } from '@anchorlib/storage';
// Create persistent storage
const appState = persistent('app-state', {
currentUser: null,
lastActivity: null,
});
// ... use the storage in your application ...
// When no longer needed, disconnect from localStorage synchronization
// This helps with memory management
persistent.leave(appState);
Best Practices
1. Naming Conventions
Use descriptive and unique names for your persistent storage instances:
// Good
const userPreferences = persistent('user-preferences@1.0.0', {});
const appSettings = persistent('myapp-settings@2.0.0', {});
// Avoid
const data = persistent('data', {});
const store = persistent('store', {});
2. Versioning
Use versioning to manage schema changes:
// Version 1.0.0
const userSettings = persistent('user-settings@1.0.0', {
theme: 'light',
});
// When you need to change the schema, increment the version
// and handle migration in your application code
const userSettings = persistent('user-settings@2.0.0:1.0.0', {
ui: {
theme: 'light',
},
});
3. Data Size Considerations
Be mindful of the amount of data you store in localStorage as browsers have storage limits:
// Good - Store only essential data
const userPreferences = persistent('user-preferences', {
theme: 'dark',
language: 'en',
});
// Avoid - Don't store large datasets
const largeDataset = persistent('large-dataset', {
// ... thousands of items ...
});
For large datasets, consider using IndexedDB instead.
4. Sensitive Data
Never store sensitive information like passwords or tokens in localStorage:
// Bad
const auth = persistent('auth', {
username: 'user',
password: 'secret123', // Never do this!
});
// Good
const userPreferences = persistent('user-preferences', {
theme: 'dark',
language: 'en',
});
5. Error Handling
Handle potential storage errors gracefully:
import { persistent } from '@anchorlib/storage';
try {
const settings = persistent('app-settings', {
theme: 'light',
});
// Use the settings
document.body.className = settings.theme;
} catch (error) {
console.error('Failed to initialize persistent storage:', error);
// Fallback to in-memory storage or default values
}
6. Memory Management
Disconnect from storage when components are unmounted or no longer needed:
import { persistent } from '@anchorlib/storage';
class MyComponent {
constructor() {
this.settings = persistent('component-settings', {
visible: true,
});
}
destroy() {
// Clean up storage connection
persistent.leave(this.settings);
}
}
Browser Compatibility
Local Storage is supported in all modern browsers:
- Chrome 4+
- Firefox 3.5+
- Safari 4+
- Edge 12+
- Internet Explorer 8+
In environments where localStorage is not available, the persistent storage will gracefully fall back to in-memory storage.
Storage Limits
Most browsers limit localStorage to 5-10 MB per origin. Be mindful of this limit when designing your storage strategy. For larger datasets, consider using IndexedDB instead.