fix(core): Fix state initialization, hash detection, and validation - v2.0.25
This commit is contained in:
126
readme.md
126
readme.md
@@ -1,12 +1,19 @@
|
||||
# @push.rocks/smartstate
|
||||
A package for handling and managing state in applications
|
||||
A powerful TypeScript library for elegant state management using RxJS and reactive programming patterns
|
||||
|
||||
## Install
|
||||
|
||||
To install `@push.rocks/smartstate`, you can use pnpm (Performant Node Package Manager). Run the following command in your terminal:
|
||||
To install `@push.rocks/smartstate`, you can use pnpm, npm, or yarn:
|
||||
|
||||
```bash
|
||||
# Using pnpm (recommended)
|
||||
pnpm install @push.rocks/smartstate --save
|
||||
|
||||
# Using npm
|
||||
npm install @push.rocks/smartstate --save
|
||||
|
||||
# Using yarn
|
||||
yarn add @push.rocks/smartstate
|
||||
```
|
||||
|
||||
This will add `@push.rocks/smartstate` to your project's dependencies.
|
||||
@@ -35,10 +42,10 @@ const myAppSmartState = new Smartstate<YourStatePartNamesEnum>();
|
||||
|
||||
When creating state parts, you can specify different initialization modes:
|
||||
|
||||
- **`'soft'`** - Allows existing state parts to remain (default behavior)
|
||||
- **`'mandatory'`** - Fails if there's an existing state part with the same name
|
||||
- **`'force'`** - Overwrites any existing state part
|
||||
- **`'persistent'`** - Enables WebStore persistence using IndexedDB
|
||||
- **`'soft'`** (default) - Returns existing state part if it exists, creates new if not
|
||||
- **`'mandatory'`** - Requires state part to not exist, fails if it does
|
||||
- **`'force'`** - Always creates new state part, overwriting any existing one
|
||||
- **`'persistent'`** - Like 'soft' but with WebStore persistence using IndexedDB
|
||||
|
||||
### Defining State Parts
|
||||
|
||||
@@ -79,6 +86,7 @@ const userStatePart = await myAppSmartState.getStatePart<IUserState>(
|
||||
You can subscribe to changes in a state part to perform actions accordingly:
|
||||
|
||||
```typescript
|
||||
// The select() method automatically filters out undefined states
|
||||
userStatePart.select().subscribe((currentState) => {
|
||||
console.log(`User Logged In: ${currentState.isLoggedIn}`);
|
||||
});
|
||||
@@ -134,6 +142,12 @@ Both methods return a Promise with the new state, giving you flexibility in how
|
||||
`StatePart` provides several useful methods for state management:
|
||||
|
||||
```typescript
|
||||
// Get current state (may be undefined initially)
|
||||
const currentState = userStatePart.getState();
|
||||
if (currentState) {
|
||||
console.log('Current user:', currentState.username);
|
||||
}
|
||||
|
||||
// Wait for a specific state condition
|
||||
await userStatePart.waitUntilPresent();
|
||||
|
||||
@@ -170,13 +184,33 @@ Persistent state automatically:
|
||||
- Restores state on application restart
|
||||
- Manages storage with configurable database and store names
|
||||
|
||||
### State Validation
|
||||
|
||||
`Smartstate` includes built-in state validation to ensure data integrity:
|
||||
|
||||
```typescript
|
||||
// Basic validation (built-in)
|
||||
// Ensures state is not null or undefined
|
||||
await userStatePart.setState(null); // Throws error: Invalid state structure
|
||||
|
||||
// Custom validation by extending StatePart
|
||||
class ValidatedStatePart<T> extends StatePart<string, T> {
|
||||
protected validateState(stateArg: any): stateArg is T {
|
||||
// Add your custom validation logic
|
||||
return super.validateState(stateArg) && /* your validation */;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
`Smartstate` includes built-in performance optimizations:
|
||||
`Smartstate` includes advanced performance optimizations:
|
||||
|
||||
- **State Change Detection**: Detects actual state changes to prevent unnecessary notifications when state values haven't truly changed
|
||||
- **Async State Hash Detection**: Uses SHA256 hashing to detect actual state changes, preventing unnecessary notifications when state values haven't truly changed
|
||||
- **Duplicate Prevention**: Identical state updates are automatically filtered out
|
||||
- **Cumulative Notifications**: Batch multiple state changes into a single notification using `notifyChangeCumulative()`
|
||||
- **Selective Subscriptions**: Use selectors to subscribe only to specific state properties
|
||||
- **Undefined State Filtering**: The `select()` method automatically filters out undefined states
|
||||
|
||||
### RxJS Integration
|
||||
|
||||
@@ -202,19 +236,75 @@ userStatePart.select(state => state.username)
|
||||
});
|
||||
```
|
||||
|
||||
### Comprehensive Usage
|
||||
### Complete Example
|
||||
|
||||
Putting it all together, `@push.rocks/smartstate` offers a flexible and powerful pattern for managing application state. By modularizing state parts, subscribing to state changes, and controlling state modifications through actions, developers can maintain a clean and scalable architecture. Combining these strategies with persistent states unlocks the full potential for creating dynamic and user-friendly applications.
|
||||
Here's a comprehensive example showcasing the power of `@push.rocks/smartstate`:
|
||||
|
||||
Key features:
|
||||
- **Type-safe state management** with full TypeScript support
|
||||
- **Reactive state updates** using RxJS observables
|
||||
- **Persistent state** with IndexedDB storage
|
||||
- **Performance optimized** with state hash detection
|
||||
- **Modular architecture** with separate state parts
|
||||
- **Action-based updates** for predictable state modifications
|
||||
```typescript
|
||||
import { Smartstate, StatePart, StateAction } from '@push.rocks/smartstate';
|
||||
|
||||
For more complex scenarios, consider combining multiple state parts, creating hierarchical state structures, and integrating with other state management solutions as needed. With `@push.rocks/smartstate`, the possibilities are vast, empowering you to tailor the state management approach to fit the unique requirements of your project.
|
||||
// Define your state structure
|
||||
type AppStateParts = 'user' | 'settings' | 'cart';
|
||||
|
||||
interface IUserState {
|
||||
isLoggedIn: boolean;
|
||||
username?: string;
|
||||
email?: string;
|
||||
}
|
||||
|
||||
interface ICartState {
|
||||
items: Array<{ id: string; quantity: number }>;
|
||||
total: number;
|
||||
}
|
||||
|
||||
// Create the smartstate instance
|
||||
const appState = new Smartstate<AppStateParts>();
|
||||
|
||||
// Initialize state parts
|
||||
const userState = await appState.getStatePart<IUserState>('user', {
|
||||
isLoggedIn: false
|
||||
});
|
||||
|
||||
const cartState = await appState.getStatePart<ICartState>('cart', {
|
||||
items: [],
|
||||
total: 0
|
||||
}, 'persistent'); // Persists across sessions
|
||||
|
||||
// Create actions
|
||||
const loginAction = userState.createAction<{ username: string; email: string }>(
|
||||
async (statePart, payload) => {
|
||||
// Simulate API call
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
return {
|
||||
isLoggedIn: true,
|
||||
username: payload.username,
|
||||
email: payload.email
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Subscribe to changes
|
||||
userState.select(state => state.isLoggedIn).subscribe(isLoggedIn => {
|
||||
console.log('Login status changed:', isLoggedIn);
|
||||
});
|
||||
|
||||
// Dispatch actions
|
||||
await loginAction.trigger({ username: 'john', email: 'john@example.com' });
|
||||
```
|
||||
|
||||
### Key Features
|
||||
|
||||
`@push.rocks/smartstate` provides a robust foundation for state management:
|
||||
|
||||
- **🎯 Type-safe** - Full TypeScript support with intelligent type inference
|
||||
- **⚡ Performance optimized** - Async state hash detection prevents unnecessary re-renders
|
||||
- **💾 Persistent state** - Built-in IndexedDB support for state persistence
|
||||
- **🔄 Reactive** - Powered by RxJS for elegant async handling
|
||||
- **🧩 Modular** - Organize state into logical, reusable parts
|
||||
- **✅ Validated** - Built-in state validation with extensible validation logic
|
||||
- **🎭 Flexible init modes** - Choose how state parts are initialized
|
||||
- **📦 Zero config** - Works out of the box with sensible defaults
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
|
Reference in New Issue
Block a user