@mirawision/wings
v1.0.0
Published
Advanced state management library for TypeScript with deep merge, request lifecycle tracking, event-driven updates, and local storage caching.
Readme
@mirawision/wings
Advanced state management library for TypeScript with deep merge, request lifecycle tracking, event-driven updates, and local storage caching. Built on top of the observer pattern, Wings provides a sophisticated yet simple way to manage complex application state.
Features
- Deep Merge State Updates: Support for nested structures and complex state updates
- Request Lifecycle Management: Automatic tracking of API requests (loading, success, error, finished)
- Event-Driven Updates: Named events with conditions for fine-grained state change handling
- Local Storage Caching: Selective data persistence with version control
- Type Safety: Full TypeScript support with generics
- Observer Pattern Integration: Reactive state updates
- Concurrent Request Tracking: Manage multiple simultaneous operations
- Cache Versioning: Automatic cache migration and invalidation
Installation
npm install @mirawision/wingsor
yarn add @mirawision/wingsNote: Wings depends on @mirawision/observer. It will be installed automatically.
Usage
Basic Example
import { Wing } from '@mirawision/wings';
interface UserState {
users: User[];
settings: Settings;
requests?: RequestsState;
}
class UserService extends Wing<UserState> {
constructor() {
super({
users: [],
settings: {},
requests: {}
});
// Define named events
this.defineEvent('userAdded', (prev, curr) =>
curr.users.length > prev.users.length
);
this.defineEvent('settingsChanged', (prev, curr) =>
JSON.stringify(prev.settings) !== JSON.stringify(curr.settings)
);
}
async fetchUsers() {
return this.executeRequest('fetchUsers',
() => api.getUsers(),
(users) => this.setState({ users }),
(error) => console.error(error)
);
}
updateSettings(newSettings: Partial<Settings>) {
this.setState({ settings: { ...this.getState().settings, ...newSettings } });
}
}Request Lifecycle Management
class DataService extends Wing<DataState> {
async fetchData() {
// Automatically manages loading, success, error states
return this.executeRequest('fetchData',
() => api.getData(),
(data) => this.setState({ data }),
(error) => console.error('Failed to fetch data:', error)
);
}
// Check request states
isDataLoading() {
return this.isRequestLoading('fetchData');
}
getDataError() {
return this.getRequestError('fetchData');
}
isDataSuccess() {
return this.isRequestSuccess('fetchData');
}
}Event-Driven State Management
class NotificationService extends Wing<NotificationState> {
constructor() {
super({ notifications: [], requests: {} });
// Define events with conditions
this.defineEvent('newNotification', (prev, curr) =>
curr.notifications.length > prev.notifications.length
);
this.defineEvent('notificationRead', (prev, curr) => {
const prevUnread = prev.notifications.filter(n => !n.read).length;
const currUnread = curr.notifications.filter(n => !n.read).length;
return currUnread < prevUnread;
});
}
// Subscribe to events
setupEventListeners() {
this.subscribeToEvent('newNotification', (prev, curr) => {
console.log('New notification received!');
this.showNotificationBadge();
});
this.subscribeToEvent('notificationRead', (prev, curr) => {
console.log('Notification marked as read');
this.updateUnreadCount();
});
}
addNotification(notification: Notification) {
this.setState({
notifications: [...this.getState().notifications, notification]
});
}
}Deep Merge State Updates
class ComplexStateService extends Wing<ComplexState> {
// Deep nested state updates
setLoadingState() {
this.setState({
requests: {
fetchNotebooks: {
loading: true,
success: false,
error: null,
finished: false
}
}
});
}
updateUserProfile(userId: string, updates: Partial<UserProfile>) {
this.setState({
users: {
[userId]: {
...this.getState().users[userId],
...updates
}
}
});
}
}Local Storage Caching
class CachedService extends Wing<CachedState> {
constructor() {
super({
users: [],
settings: {},
requests: {}
}, {
enabled: true,
cacheKeys: ['users', 'settings'], // Only cache users and settings
storageKey: 'user-service-cache',
version: '1.0.0'
});
}
// Cache will be automatically saved and loaded
// Clear cache when needed
clearCache() {
this.clearCache();
}
// Check cache status
isCacheEnabled() {
return this.isCacheEnabled();
}
}React Integration
import React, { useEffect, useState } from 'react';
import { Wing } from '@mirawision/wings';
interface AppState {
theme: 'light' | 'dark';
user: User | null;
requests?: RequestsState;
}
class AppService extends Wing<AppState> {
constructor() {
super({
theme: 'light',
user: null,
requests: {}
});
}
toggleTheme() {
const currentTheme = this.getState().theme;
this.setState({ theme: currentTheme === 'light' ? 'dark' : 'light' });
}
}
// React Hook
function useWing<T>(wing: Wing<T>): T {
const [state, setState] = useState<T>(wing.getState());
useEffect(() => {
const unsubscribe = wing.subscribe((message) => {
setState(message.payload.currentState);
});
return unsubscribe;
}, [wing]);
return state;
}
// Usage in component
function App() {
const appService = new AppService();
const state = useWing(appService);
return (
<div>
<button onClick={() => appService.toggleTheme()}>
Current theme: {state.theme}
</button>
</div>
);
}API Reference
Wing
Advanced state management class that extends the Observer pattern.
Constructor
constructor(initialState: T, cacheConfig?: CacheConfig)Methods
setState(newState: T | Partial<T>): void- Updates state with deep merge support
- Triggers event notifications
- Persists to cache if enabled
getState(): T- Returns current state
defineEvent(eventName: string, condition: EventCondition<T>): void- Defines a named event with condition
subscribeToEvent(eventName: string, callback: (prev: T, curr: T) => void): () => void- Subscribes to a named event
- Returns unsubscribe function
executeRequest<TResult>(requestName: string, apiCall: () => Promise<TResult>, onSuccess?: (result: TResult) => void, onError?: (error: string) => void): Promise<TResult | null>- Executes API request with automatic state management
isRequestLoading(requestName: string): boolean- Checks if request is loading
isRequestSuccess(requestName: string): boolean- Checks if request succeeded
getRequestError(requestName: string): string | null- Gets request error message
clearCache(): void- Clears cached data
Type Definitions
interface BaseState {
requests?: RequestsState;
}
interface RequestState {
loading: boolean;
success: boolean;
error: string | null;
finished: boolean;
}
interface CacheConfig {
enabled: boolean;
cacheKeys: (keyof any)[];
storageKey?: string;
version?: string;
}Contributing
Contributions are always welcome! Feel free to open issues or submit pull requests.
License
This project is licensed under the MIT License.
