state-guardian v0.1.0
Custom State Manager for Angular - STATE GUARDIAN
Introduction
The Custom State Manager is designed by Michael Egbo to manage state, side effects, and more in Angular applications, ensuring a streamlined and efficient workflow.
Features
State Management store
- Manages and tracks the state of different parts of the application using the
CustomStore
. - Allows for selecting specific slices of the state for observation.
dispatch:
Purpose: Used to dispatch an action to update the state. When to Use: You use dispatch when you want to trigger a change in the application state. It's typically used when you need to update the state based on user interactions or other events. Example: When a user logs in, you may dispatch an action to update the user's login status in the state.
select:
Purpose: Used to select and observe specific parts of the application state. When to Use: You use select when you want to "listen" to changes in a specific part of the state. It allows you to react to state changes and update your component's properties accordingly. Example: You might use select to watch for changes in the user's login status or other parts of the state and take specific actions in response to those changes.
2. Effects Handling:
- Manages side effects, especially asynchronous operations like HTTP requests.
- Updates the state based on the result of these side effects.
3. Middleware Integration:
- Intercepts actions to introduce additional behavior or side effects.
- Useful for logging, analytics, or any other cross-cutting concerns.
4. Entity Management Utilities:
- Provides utilities to manage collections of entities efficiently.
- Supports operations like adding one or many entities, updating, and deleting entities.
5. Data Normalization:
- Transforms nested or complex data structures into a flat, consistent format.
- Helps in efficiently managing and querying data.
6. Caching Mechanism:
- Caches frequently accessed data to reduce the need for repeated network requests.
- Improves performance and can provide offline data access.
7. Error Handling:
- Handles errors during side effects and updates the state accordingly.
- Provides a consistent way to manage and display errors to users.
8. Flexible API Calls:
- The effects service can handle both direct HTTP calls and calls through provided services, offering flexibility in how backend interactions are managed.
9. Immutable State Updates:
- Ensures that state updates are immutable, leading to predictable state changes and easier debugging.
10. Integration with External Libraries:
- Designed to work seamlessly with libraries like RxJS, making it easier to handle asynchronous operations and reactive programming patterns.
11. Modularity and Reusability:
- Components like the store, middleware, and effects are modular, allowing for reuse across different parts of the application or even different applications.
State Guardian Library Documentation
State Guardian is a powerful state management library for Angular applications. It provides various features for managing application state, handling asynchronous effects, managing entities, normalizing data, caching, and more. This documentation will guide you through the installation and usage of State Guardian.
Installation
To install the state-guardian
library in your Angular project, follow these steps:
Using npm
npm install state-guardian
Using yarn
yarn add state-guardian
Usage
Import the StateGuardianModule
In your Angular application, you should import and add the StateGuardianModule
to your application's module. Here's an example of how to do this:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StateGuardianModule } from 'state-guardian'; // Import the StateGuardianModule
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, StateGuardianModule], // Add StateGuardianModule to your imports
bootstrap: [AppComponent],
})
export class AppModule {}
Using StateGuardian Services
Now that you have imported the StateGuardianModule
, you can use StateGuardian services in your Angular components and services. Below are examples of how to use various features of State Guardian:
State Management
- Initialization:
const INITIAL_STATE: AppState = {
user: { ... },
books: [],
...
};
this.store.dispatch(() => INITIAL_STATE);
- Selection:
this.store.select('user').subscribe(userState => {
this.currentUser = userState;
});
Effects Handling
For login:
const loginEffectConfig: EffectConfig = {
apiCall: () => this.authService.login(credentials),
successHandler: (response) => { return { user: { ...response, isLoggedIn: true } }; },
errorHandler: (error) => { return { user: { error, isLoggedIn: false } }; }
};
this.effectsService.handleEffect(loginEffectConfig);
Example use case below
import {
CustomStore,
EffectsService,
} from 'state-guardian';
interface User {
id: number;
username: string;
token: string;
}
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
})
export class LoginComponent implements OnInit {
form: UntypedFormGroup;
isLoading = false;
constructor(
private authService: AuthService,
private router: Router,
private userService: UserService,
private fb: UntypedFormBuilder,
private store: CustomStore<{ user: User }>,
private effectsService: EffectsService
) {}
ngOnInit(): void {
this.form = this.fb.group({
email: ['', [Validators.required]],
password: ['', [Validators.required]],
});
// Watch for changes in the 'user' state and react accordingly
this.store.select('user').subscribe((userState: User) => {
this.isLoading = userState.isLoading;
if (userState.isLoggedIn) {
this.router.navigateByUrl('/home');
}
if (userState.error) {
Swal.fire('Hi...', 'Kindly check your username or password', 'warning');
}
});
}
onSubmit() {
if (!this.form.valid) {
Swal.fire('Hi...', 'Kindly check your username or password', 'warning');
return;
}
const credentials = {
email: this.form.value.email,
password: this.form.value.password,
};
this.isLoading = true;
this.effectsService.handleEffect(
() => this.fakeLogin(credentials).pipe(take(1)),
(response: User) => {
localStorage.a = new Date();
this.authService.setUserLoggedIn(true);
this.userService.setToken(response.token);
// Dispatch the updated user state to the store
this.store.dispatch(() => ({ user: response }));
logEvent(getAnalytics(), 'login', { method: 'Password' });
this.router.navigateByUrl('/home');
},
(error: any) => {
Swal.fire('Hi...', 'Kindly check your username or password', 'warning');
logEvent(getAnalytics(), 'login_failed', { method: 'Password' });
this.isLoading = false;
}
);
}
// Simulated login API call, replace with your actual login logic
private fakeLogin(credentials: { email: string; password: string }) {
return new Observable<User>((observer) => {
setTimeout(() => {
if (credentials.email === 'user@example.com' && credentials.password === 'password') {
const user: User = {
id: 1,
username: 'example_user',
token: 'example_token',
};
observer.next(user);
} else {
observer.error('Invalid credentials');
}
observer.complete();
}, 1000);
});
}
}
Entity Management
- Adding a new book:
const newBook: Book = { title: 'New Title', author: 'John Doe' };
const updatedBooks = this.entityService.addOne(this.books, newBook);
this.store.dispatch(() => { books: updatedBooks });
Middleware Integration
Use the middleware to log actions:
this.middlewareService.intercept('ADD_BOOK', newBook);
Data Normalization
When fetching nested data, use normalization:
const nestedBooks = [
{ id: 1, title: 'Title 1', author: { name: 'Author 1' } },
{ id: 2, title: 'Title 2', author: { name: 'Author 2' } }
];
const normalizedBooks = this.normalizationService.normalize(nestedBooks, 'id');
this.store.dispatch(() => { books: normalizedBooks });
Caching
Cache data after fetching:
this.cacheService.set('books', this.books);
Retrieve cached data:
const cachedBooks = this.cacheService.get('books');
Use Case: Book Management App
Login: Use the
EffectsService
for login and set user tokens upon success.Fetch Books: After logging in, fetch the books. Use normalization to flatten the data and cache it for faster subsequent access.
Manage Books: Add, update, or delete books using the
EntityManagementService
.Middleware: Log actions using the middleware, providing insights into the user's behavior.
This documentation gives a more in-depth overview of how to use the state manager and its features. Adjust paths, method names, and data structures to fit your actual implementation.
Author: Michael Egbo Email: https://www.linkedin.com/in/michaelegbo/ Package - https://www.npmjs.com/package/state-guardian
TO Contribute see - https://github.com/michaelegbo/State-Guardian