State Management
Learn how to manage state effectively with Storken.
Basic State Operations
Setting State
Set state directly with values or use callback functions:
const [count, setCount] = useStorken('count', 0)
// Direct value
setCount(10)
// Callback function (like useState)
setCount(prev => prev + 1)
// Async updates
const handleUpdate = async () => {
const newValue = await fetchValue()
setCount(newValue)
}
Resetting State
Reset state to its initial value:
const [count, setCount, resetCount] = useStorken('count', 0)
// Reset to initial value (0)
resetCount()
// Reset multiple states
const [user, , resetUser] = useStorken('user')
const [theme, , resetTheme] = useStorken('theme')
const resetAll = () => {
resetUser()
resetTheme()
resetCount()
}
Global State Management
State is automatically shared across all components using the same key:
// Header.tsx
function Header() {
const [user] = useStorken<User>('user')
return <div>Welcome, {user?.name}</div>
}
// Profile.tsx
function Profile() {
const [user, setUser] = useStorken<User>('user')
const updateName = (name: string) => {
setUser({ ...user, name })
}
return (
<input
value={user?.name}
onChange={e => updateName(e.target.value)}
/>
)
}
// Both components share the same 'user' state
Complex State Updates
Array State
const [todos, setTodos] = useStorken<Todo[]>('todos', [])
// Add item
const addTodo = (todo: Todo) => {
setTodos(prev => [...prev, todo])
}
// Remove item
const removeTodo = (id: string) => {
setTodos(prev => prev.filter(t => t.id !== id))
}
// Update item
const updateTodo = (id: string, updates: Partial<Todo>) => {
setTodos(prev => prev.map(t =>
t.id === id ? { ...t, ...updates } : t
))
}
// Sort items
const sortByDate = () => {
setTodos(prev => [...prev].sort((a, b) =>
a.createdAt.getTime() - b.createdAt.getTime()
))
}
Object State
interface Settings {
theme: 'light' | 'dark'
notifications: boolean
language: string
privacy: {
shareData: boolean
showProfile: boolean
}
}
const [settings, setSettings] = useStorken<Settings>('settings', {
theme: 'light',
notifications: true,
language: 'en',
privacy: {
shareData: false,
showProfile: true
}
})
// Update single property
setSettings(prev => ({ ...prev, theme: 'dark' }))
// Update nested property
setSettings(prev => ({
...prev,
privacy: {
...prev.privacy,
shareData: true
}
}))
// Batch updates
const updateSettings = (updates: Partial<Settings>) => {
setSettings(prev => ({ ...prev, ...updates }))
}
State with Side Effects
Use setters to trigger side effects when state changes:
const [useStorken] = create({
setters: {
// Save to backend when cart changes
cart: async (storken, items: CartItem[]) => {
await fetch('/api/cart', {
method: 'PUT',
body: JSON.stringify(items)
})
// Update related states
const total = items.reduce((sum, item) =>
sum + item.price * item.quantity, 0
)
storken.sky.set('cartTotal', total)
},
// Log state changes
user: async (storken, user: User) => {
console.log('User updated:', user)
// Track analytics
analytics.track('user_update', {
userId: user.id,
timestamp: Date.now()
})
}
}
})
// Usage - side effects run automatically
const [cart, setCart, , loading] = useStorken('cart')
// loading becomes true during side effect execution
Optimistic Updates
Update UI immediately while syncing with backend:
const [useStorken] = create({
setters: {
todos: async (storken, todos: Todo[], optimistic = true) => {
// Optimistically update UI first
if (optimistic) {
storken.set(todos)
}
try {
// Sync with backend
const response = await fetch('/api/todos', {
method: 'PUT',
body: JSON.stringify(todos)
})
if (!response.ok) {
throw new Error('Failed to save')
}
// Update with server response if different
const serverTodos = await response.json()
if (!optimistic) {
storken.set(serverTodos)
}
} catch (error) {
// Revert on error
console.error('Failed to save todos:', error)
storken.reset() // Revert to previous state
throw error
}
}
}
})
State Persistence
Persist state across sessions using plugins:
// Create persistence plugin
const persistPlugin = (storken) => {
const key = `app_${storken.key}`
// Load from localStorage on init
const saved = localStorage.getItem(key)
if (saved) {
try {
storken.set(JSON.parse(saved))
} catch (e) {
console.error('Failed to load persisted state:', e)
}
}
// Save to localStorage on change
storken.on('set', (value) => {
try {
localStorage.setItem(key, JSON.stringify(value))
} catch (e) {
console.error('Failed to persist state:', e)
}
})
return {
clear: () => localStorage.removeItem(key),
isPersisted: () => localStorage.getItem(key) !== null
}
}
// Use with selected states
const [useStorken] = create({
initialValues: {
theme: 'light',
user: null,
tempData: {} // Not persisted
},
plugins: {
persist: persistPlugin
}
})
// Access persistence methods
const [theme, , , , , plugins] = useStorken('theme')
plugins.persist.clear() // Clear persisted data
✅ Best Practices
- • Keep state minimal - derive what you can
- • Use callbacks for updates based on previous state
- • Handle errors in async operations
- • Use TypeScript for type safety
- • Consider using setters for side effects
- • Implement optimistic updates for better UX