enablePersist
The enablePersist module in Igris enables state persistence across page reloads and browser sessions. It provides flexible configuration options for storage management, migration, and state merging strategies.
Basic Usage
Enabling Persistence
import { createStore } from "igris";
import { enablePersist } from "igris/persistence";
const useStore = createStore(
{ theme: "light" },
({ set }) => ({
toggleTheme: () => set(state => ({
theme: state.theme === "light" ? "dark" : "light"
}))
}),
{
name: "app-settings",
persist: enablePersist()
}
);
Configuration Options
PersistConfig
Interface
interface PersistConfig<T> {
// Debounce time in milliseconds (default: 100ms)
debounceTime?: number;
// Version number for migrations
version?: number;
// Migration function
migrate?: (
storedValue: DeepPartial<T> | T,
version?: number
) => DeepPartial<T>;
// Partial state selector
partial?: (state: T) => Partial<T> | T;
// State merge strategy
merge?: (
initialValue: T,
storedValue: DeepPartial<T>
) => DeepPartial<T>;
// Custom storage provider
storage?: StorageProvider;
// Skip hydration
skipHydrate?: boolean;
}
Storage Provider Types
type StorageProvider = ActualStorage | (() => ActualStorage);
interface ActualStorage {
getItem: (name: string) => Promise<string | null> | string | null;
setItem: (name: string, value: string) => Promise<void> | void;
removeItem: (name: string) => Promise<void> | void;
}
Advanced Usage
Custom Storage Provider
const usePersistedStore = createStore(
initialState,
actions,
{
name: "my-store",
persist: enablePersist({
// For client-side frameworks
storage: localStorage
// For server-side rendering frameworks
storage: () => localStorage
// Custom storage implementation
storage: {
getItem: async (key) => { /* ... */ },
setItem: async (key, value) => { /* ... */ },
removeItem: async (key) => { /* ... */ }
}
})
}
);
State Migration
const useStore = createStore(
initialState,
actions,
{
name: "versioned-store",
persist: enablePersist({
version: 2,
migrate: (stored, version) => {
if (version === 1) {
// Migrate from v1 to v2
return {
...stored,
newField: 'default'
};
}
return stored;
}
})
}
);
Partial Persistence
const useStore = createStore(
{
user: { name: '', settings: {} },
temporaryData: {}
},
actions,
{
name: "partial-store",
persist: enablePersist({
// Only persist user data
partial: (state) => ({
user: state.user
})
})
}
);
Custom Merge Strategy
const useStore = createStore(
initialState,
actions,
{
name: "merge-store",
persist: enablePersist({
merge: (initial, stored) => ({
...initial,
...stored,
// Custom merge logic
settings: {
...initial.settings,
...stored.settings
}
})
})
}
);
Debounced Persistence
const useStore = createStore(
initialState,
actions,
{
name: "debounced-store",
persist: enablePersist({
// Save state changes after 500ms of inactivity
debounceTime: 500
})
}
);
Server-Side Rendering
const useStore = createStore(
initialState,
actions,
{
name: "ssr-store",
persist: enablePersist({
// Use function to ensure localStorage is only accessed client-side
storage: () => localStorage,
// Skip initial hydration if needed
skipHydrate: true
})
}
);
Best Practices
-
Storage Selection
- Use
localStorage
for long-term persistence - Use
sessionStorage
for session-only persistence - Implement custom storage for special needs (e.g., encrypted storage)
- Use
-
Version Management
- Always include a version when using migrations
- Implement migrations for backward compatibility
- Test migration paths thoroughly
-
Performance Optimization
- Use
partial
to persist only necessary data - Adjust
debounceTime
based on update frequency - Consider
skipHydrate
for SSR applications
- Use
-
Security Considerations
- Don't persist sensitive information in localStorage
- Consider implementing encryption for sensitive data
- Validate stored data before using it