Persistence plugin for valtio using valtio-plugin architecture
npm install valtio-persist-pluginA persistence plugin for valtio using the valtio-plugin architecture.
- Built on valtio-plugin architecture
- Multiple storage backends (localStorage, sessionStorage, IndexedDB, AsyncStorage)
- Path-based filtering - persist only what you need
- Pluggable serialization and merge strategies
- Debounced persistence for performance
- Tree-shakeable - only import what you use
``bash`
npm install valtio valtio-plugin valtio-persist-plugin
`typescript
// store.ts
// IMPORTANT - import the proxy from 'valtio-plugin' instead of valtio
import { proxy } from 'valtio-plugin'
import { createPersistPlugin } from 'valtio-persist-plugin'
// initialize the plugin with the key to store the data with
const persist = createPersistPlugin('mydata')
// attach the plugin to the global valtio proxy
proxy.use(persist)
// create your state
const store = proxy({
count: 0
})
// hydrate from storage - you can do this at whatever point suits you best
await persist.hydrate(store)
`
`typescript
// App.tsx
import { useSnapshot } from 'valtio'
import { store } from './store'
const App = () => {
const snap = useSnapshot(store)
return (
export default App
`
That's it. Your data will now be stored into localStorage (that's the default).
`typescript
import {
LocalStorageStrategy, // Default - browser localStorage
SessionStorageStrategy, // Browser sessionStorage
MemoryStorageStrategy, // In-memory (testing)
} from 'valtio-persist-plugin'
proxy.use(createPersistPlugin('session-data', {
storage: SessionStorageStrategy
}))
`
`typescript
import { IndexedDBStorage } from 'valtio-persist-plugin/indexed-db'
proxy.use(createPersistPlugin('large-data', {
storage: IndexedDBStorage
}))
`
`typescript
import { AsyncStorage } from 'valtio-persist-plugin/async-storage'
proxy.use(createPersistPlugin('mobile-state', {
storage: AsyncStorage
}))
`
File system storage is planned and will be here soon.
Persist only specific parts of your state:
`typescript
proxy.use(createPersistPlugin('auth', {
paths: ['token', 'user'] // Only persist these top-level keys
}))
const store = proxy({
token: '',
user: null,
tempData: {}, // Not persisted
ui: {} // Not persisted
})
`
valtio-plugin gives us the ability to scope our state into different 'instances'. This allows us to have multiple different stores that all have different types of strategies.
`typescript
import { proxy } from 'valtio-plugin'
import { createPersistPlugin, SessionStorageStrategy } from 'valtio-persist-plugin'
import { IndexedDBStorage } from 'valtio-persist-plugin/indexed-db'
const userProxy = proxy.createInstance()
const dataProxy = proxy.createInstance()
// Session data in sessionStorage
const userPersist = createPersistPlugin('session', {
storage: SessionStorageStrategy,
paths: ['auth', 'preferences.theme']
})
userProxy.use(userPersist)
const userStore = userProxy({
auth: { token: '', user: null},
preferences: {
theme: 'dark',
ui: {
sidebar: true // not persisted
}
}
})
// Large data in IndexedDB
const dataPersist = createPersistPlugin('data', {
storage: IndexedDBStorage,
paths: ['documents', 'cache']
})
dataProxy.use(dataPersist)
const dataStore = dataProxy({
documents: [],
cache: {}
})
// Hydrate both
await userPersist.hydrate(userStore)
await dataPersist.hydrate(dataStore)
`
Once registered, the plugin exposes these methods:
`typescript
const myProxyInstance = proxy.createInstance()
const myPersist = createPersistPlugin('my-store')
myProxyInstance.use(myPersist)
const store = myProxyInstance({ count: 0 })
// Hydrate from storage
await myPersist.hydrate(store)
// Manually trigger persistence
await myPersist.persist(store)
// Clear persisted data
await myPersist.clear()
// Check hydration status
if (myPersist.isHydrated()) {
console.log('Ready!')
}
// Get the storage key
console.log(myPersist.getKey()) // 'my-store'
`
`typescript
interface PersistPluginOptions
// Storage backend (default: LocalStorageStrategy)
storage?: StorageStrategy
// Serialization strategy (default: JSONSerializationStrategy)
serialization?: SerializationStrategy
// Merge strategy (default: DefaultMergeStrategy)
merge?: MergeStrategy
// Paths to persist (default: entire state (empty))
paths?: string[]
// Debounce time in ms (default: 100)
debounceTime?: number
// Conditional persistence
shouldPersist?: (path: string[], value: unknown, state: T) => boolean
}
`
`typescript
import { DefaultMergeStrategy } from 'valtio-persist-plugin'
// Stored: { count: 5 }
// Initial: { count: 0, name: '' }
// Result: { count: 5, name: '' }
`
`typescript
import { DeepMergeStrategy } from 'valtio-persist-plugin'
proxy.use(createPersistPlugin('nested', {
merge: DeepMergeStrategy
}))
// Stored: { user: { name: 'John' } }
// Initial: { user: { name: '', age: 0 } }
// Result: { user: { name: 'John', age: 0 } }
`
`typescript
import type { StorageStrategy } from 'valtio-persist-plugin'
const MyCloudStorage: StorageStrategy
isAsync: true,
async get(key: string): Promise
// Fetch from your cloud storage
const response = await fetch(https://api.example.com/storage/${key})
if (!response.ok) return null
return response.text()
},
async set(key: string, value: string): Promise
// Save to your cloud storage
await fetch(https://api.example.com/storage/${key}, {
method: 'PUT',
body: value
})
},
async remove(key: string): Promise
// Delete from your cloud storage
await fetch(https://api.example.com/storage/${key}, {
method: 'DELETE'
})
},
}
proxy.use(createPersistPlugin('cloud', {
storage: MyCloudStorage
}))
`
Full TypeScript support with generics:
`typescript
interface AppState {
user: { name: string; email: string } | null
preferences: { theme: 'light' | 'dark' }
cache: Record
}
proxy.use(createPersistPlugin
paths: ['user', 'preferences']
}))
const store = proxy
user: null,
preferences: { theme: 'dark' },
cache: {}
})
`
If you're coming from the original valtio-persist:
`typescript
// Before (valtio-persist)
const { store } = await persist(
{ count: 0 },
'my-key',
{ storageStrategy: SessionStorageStrategy }
)
// After (valtio-persist-plugin)
import { proxy } from 'valtio-plugin'
import { createPersistPlugin, SessionStorageStrategy } from 'valtio-persist-plugin'
const persist = createPersistPlugin('my-key', {
storage: SessionStorageStrategy
})
proxy.use(persist)
const store = proxy({ count: 0 })
await persist.hydrate(store)
``
The plugin approach gives you:
- Composition with other valtio-plugin plugins
- Path-based filtering for multiple storage backends
- More explicit control over hydration timing
- Scoped instances with different persistence strategies
MIT