@dbs-portal/core-store
v1.0.0
Published
Global state management with Zustand for DBS Portal
Maintainers
Readme
@dbs-portal/core-store
Enhanced global state management with Zustand for DBS Portal, featuring immutable updates with Immer, runtime validation with Zod, and comprehensive middleware support.
Features
🔧 Core Capabilities
- Zustand-based state management with TypeScript support
- Immer integration for immutable state updates
- Zod validation for runtime type checking and data integrity
- Persistence middleware with customizable storage options
- DevTools integration for development debugging
- Backward compatibility with existing store implementations
🎯 Enhanced Features
- State validation with custom error handling
- Async action utilities with automatic loading states
- Computed values (derived state) with memoization
- Selector utilities for optimized component subscriptions
- Middleware composition for extensible functionality
Installation
This package is part of the DBS Portal monorepo and includes all necessary dependencies:
# Dependencies are automatically managed
yarn installQuick Start
Basic Enhanced Store
import { createEnhancedStore } from '@dbs-portal/core-store'
import { z } from 'zod'
// Define validation schema
const CounterSchema = z.object({
count: z.number(),
step: z.number().positive()
})
type CounterState = z.infer<typeof CounterSchema> & {
increment: () => void
decrement: () => void
setStep: (step: number) => void
reset: () => void
}
// Create enhanced store
export const useCounterStore = createEnhancedStore<CounterState>(
(set) => ({
count: 0,
step: 1,
// Immer allows direct mutations
increment: () => set((state) => {
state.count += state.step
}),
decrement: () => set((state) => {
state.count -= state.step
}),
setStep: (step: number) => set((state) => {
state.step = step
}),
reset: () => set((state) => {
state.count = 0
state.step = 1
})
}),
{
name: 'Counter Store',
immer: true,
validation: {
schema: CounterSchema,
enabled: process.env.NODE_ENV === 'development'
},
persist: {
key: 'counter-store',
options: {
partialize: (state) => ({ count: state.count })
}
}
}
)Using the Enhanced Root Store
import { useEnhancedStore } from '@dbs-portal/core-store'
function MyComponent() {
const {
theme,
setTheme,
notifications,
success,
isLoading
} = useEnhancedStore()
const handleThemeChange = () => {
setTheme(theme === 'light' ? 'dark' : 'light')
}
const showNotification = () => {
success('Success!', 'Operation completed successfully')
}
return (
<div>
<button onClick={handleThemeChange}>
Current theme: {theme}
</button>
<button onClick={showNotification}>
Show Notification
</button>
{isLoading && <div>Loading...</div>}
</div>
)
}Advanced Usage
State Validation
import { createEnhancedStore } from '@dbs-portal/core-store'
import { z } from 'zod'
const UserSchema = z.object({
id: z.string(),
name: z.string().min(1),
email: z.string().email(),
role: z.enum(['admin', 'user', 'guest'])
})
const store = createEnhancedStore(
(set) => ({
users: [],
addUser: (user) => set((state) => {
state.users.push(user)
})
}),
{
validation: {
schema: z.object({
users: z.array(UserSchema)
}),
enabled: true,
onError: (error) => {
console.error('Validation failed:', error)
// Handle validation errors
}
}
}
)Async Actions with Loading States
import { createAsyncAction } from '@dbs-portal/core-store'
const useAsyncActions = {
fetchData: createAsyncAction(useMyStore, 'fetchData')
}
// Usage
const handleFetch = async () => {
await useAsyncActions.fetchData(async () => {
const response = await fetch('/api/data')
const data = await response.json()
useMyStore.getState().setData(data)
})
}Computed Values
import { createComputed } from '@dbs-portal/core-store'
const useDoubledCount = createComputed(
useCounterStore,
(state) => state.count * 2
)
const useFilteredUsers = createComputed(
useUserStore,
(state) => state.users.filter(user => user.isActive),
(a, b) => a.length === b.length // Custom equality function
)Custom Middleware
import { createStoreWithMiddleware } from '@dbs-portal/core-store'
const store = createStoreWithMiddleware(
(set, get) => ({
// Your state and actions
}),
{
immer: true,
persist: {
key: 'my-store',
options: {
version: 1,
migrate: (persistedState, version) => {
// Handle migrations
return persistedState
}
}
},
devtools: {
name: 'My Store',
enabled: process.env.NODE_ENV === 'development'
},
validation: {
schema: MySchema,
enabled: true
}
}
)API Reference
Core Functions
createEnhancedStore<T>(initializer, options)
Creates an enhanced store with middleware support.
Parameters:
initializer: Store state and actions initializer functionoptions: Configuration options for middleware
Options:
name: Store name for debuggingimmer: Enable immer middleware (default: true)persist: Persistence configurationdevtools: DevTools configurationvalidation: State validation configurationmiddleware: Custom middleware array
createStoreWithMiddleware<T>(initializer, middlewareConfig)
Alternative API for creating stores with middleware configuration.
createEnhancedRootStore(config)
Creates the enhanced root store with all application state.
Utility Functions
createSelectors(useStore)
Creates typed selectors for store properties.
createActions(useStore)
Extracts action functions from store.
createComputed(useStore, selector, equalityFn?)
Creates computed/derived values with memoization.
createAsyncAction(useStore, key)
Creates async action wrapper with loading state management.
Migration Guide
From Legacy Store
The enhanced store is fully backward compatible. You can gradually migrate:
// Legacy usage (still works)
import { useStore } from '@dbs-portal/core-store'
// Enhanced usage (new features)
import { useEnhancedStore } from '@dbs-portal/core-store'Adding Validation
// Before
const store = createStore(initializer)
// After
const store = createEnhancedStore(initializer, {
validation: {
schema: MySchema,
enabled: process.env.NODE_ENV === 'development'
}
})Best Practices
- Use Immer for Complex Updates: Leverage immer's draft mutations for cleaner code
- Validate in Development: Enable validation during development for better DX
- Partition Persistence: Only persist necessary state to reduce storage usage
- Use Computed Values: Create derived state with
createComputedfor performance - Handle Async Actions: Use
createAsyncActionfor consistent loading states
TypeScript Support
Full TypeScript support with:
- Type-safe state and actions
- Inferred types from Zod schemas
- Generic store creation
- Typed selectors and computed values
Performance
- Tree-shaking: Only bundle used middleware
- Selective subscriptions: Use selectors to prevent unnecessary re-renders
- Memoized computations: Computed values are automatically memoized
- Optimized persistence: Configurable state partitioning
License
MIT - Part of the DBS Portal monorepo.
