0.1.0 • Published 8 months ago

state-guardian v0.1.0

Weekly downloads
-
License
-
Repository
-
Last release
8 months ago

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

  1. Initialization:
const INITIAL_STATE: AppState = {
  user: { ... },
  books: [],
  ...
};
this.store.dispatch(() => INITIAL_STATE);
  1. 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

  1. Login: Use the EffectsService for login and set user tokens upon success.

  2. Fetch Books: After logging in, fetch the books. Use normalization to flatten the data and cache it for faster subsequent access.

  3. Manage Books: Add, update, or delete books using the EntityManagementService.

  4. 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

0.1.0

8 months ago

0.0.9

8 months ago

0.0.8

8 months ago

0.0.7

8 months ago

0.0.6

8 months ago

0.0.5

8 months ago

0.0.4

8 months ago

0.0.3

8 months ago

0.0.2

8 months ago

0.0.1

8 months ago