Giter Site home page Giter Site logo

gernsdorfer / ngrx-lite Goto Github PK

View Code? Open in Web Editor NEW
18.0 4.0 0.0 8.9 MB

A NGRX Component Store with benefits

Home Page: https://gernsdorfer.github.io/ngrx-lite/

License: MIT License

TypeScript 91.60% JavaScript 2.53% HTML 4.97% CSS 0.81% SCSS 0.09%
ngrx-store angular redux redux-devtools ngrx ngrx-component-store

ngrx-lite's Introduction

Test, Lint, Build Publish to NPM styled with PRs coverage ngrx-lite

NgRxLite

A small Angular state mangement based on NgRx ComponentStore, with some benefits ๐Ÿ˜Ž

Synopsis

The current @ngrx/component-store implementation works with its own isolated store. Unfortunately, there is no connection to the global @ngrx/store or the @ngrx/store-devtools.

This Library connects your @ngrx/component-store with the @ngrx/store to share and debug the @ngrx/actions and store.

Benefits

  • ๐Ÿค same API as @ngrx/component-store with optional parameters
  • โฑ fast and easy creation of a dynamic Redux store
  • โณ optional integrated loading state for effects
  • ๐Ÿคฏ debuging of application state across different routes
  • โš’๏ธ Redux DevTools support for NgRxLite ComponentsStore for
    • patchState
    • setState
    • createdLoadingEffects
  • ๐Ÿ’ฝ supports session storage and local storage
  • ๐Ÿ˜ freedom to decide where the store is located: root, module or in the component scope
  • ๐Ÿ”› share the state changes and actions in the NgRx store
  • ๐Ÿ“‘ store the form data for persistance and debugging
  • ๐Ÿ‘‚ create effects for global storage
  • โœ๏ธ write the tests is much easier

  • ๐Ÿ‘ฉโ€๐Ÿ’ป checkout the sample app
  • โ–ถ๏ธ Play with a Demo
  • ๐Ÿ“– read the docs

Install

Yarn

yarn add @ngrx/store @ngrx/effects @ngrx/component-store @ngrx/store-devtools @gernsdorfer/ngrx-lite

NPM

npm install @ngrx/store @ngrx/effects @ngrx/component-store @ngrx/store-devtools @gernsdorfer/ngrx-lite

Usage

  1. import the StoreModule from NgRx to the root module
@NgModule({
  // ...
  imports: [StoreModule.forRoot({})]
// ...
  1. create the store with the same API as @ngrx/component-store
export interface MyState {
  counter: number;
}

@Component({
  selector: 'my-component',
  template: '<button (click)="load(\'test\')">',
})
class MyComponent implements OnDestroy {
  // create a componentStore
  private store = this.storeFactory.createComponentStore<MyState>({
    storeName: 'BASIC_COUNTER',
    defaultState: { counter: 0 },
  });
  // read the state
  public counterState$: Observable<MyState> = this.store.state$;

  constructor(private storeFactory: StoreFactory) {}

  increment(counter: number) {
    // patch your state
    this.store.patchState({ counter });
  }

  ngOnDestroy() {
    // destory the store
    this.store.ngOnDestroy();
  }
}

That's it ๐Ÿฅณ

Features

DevTools support

Install and import ngrx/store-devtools und have all the features from the DevTools for your component store.

It's important to set the monitor property in your StoreDevtoolsOptions, otherwise a state import is not possible.

@NgModule({
  imports: [
    StoreDevtoolsModule.instrument({
      name: 'ngrx-lite-demo',
      maxAge: 25,
      logOnly: false,
      // set the monitor property here
      monitor: (state, action) => action,
    }),

  ],
})

Let's take a look at Redux DevTools and what happens in the example above.

Store is initialized

After the store is initialized you can find the store in the @ngrx/devtools.

State-Init

Patch state

After patch state you see this in your Redux DevTools. It's possbile to define an custom action name for your patch/set state.

State-Init

Router store

Import the RouterStoreModule into your main application to debug your state across all visited URLs. This module stores related URLs to the current store.

So it's possible to replay your state changes by revisiting the related url.

@NgModule({
  //...
  imports: [RouterStoreModule]
//...

Loading store

Create ComponentLoadingStore to set a Loader State while an Effect is running. You have the same API as createComponentStore with an extra method loadingEffect.

type State = LoadingStoreState<{ counter: number }, { message: string }>;

@Component({
  selector: 'my-app-basic-app',
  templateUrl: 'loading-effect.html',
})
export class LoadingEffectComponent implements OnDestroy {
  // create your loading store
  private store = this.storeFactory.createComponentLoadingStore<State['item'], State['error']>({
    storeName: 'LOADING_STORE',
  });

  // read the state
  public counterState$: Observable<State> = this.store.state$;

  // define your loadingEffect to change the state
  public increment = this.store.loadingEffect('increment', (counter: number = 0) => of(counter + 1));

  constructor(private storeFactory: StoreFactory) {}

  ngOnDestroy() {
    // destory the store
    this.counterStore.ngOnDestroy();
  }
}

Let's take a look at Redux DevTools and what happens in the example above.

Store is initialized

After the store is initialized you can find the store in the @ngrx/devtools.

State-Init

Loader state isLoading changed

For a running Effect isLoading is true and you can show a spinner in your UI.

State-Loading

Effect successfully executed

After an effect was successfully executed the item key is updated.

State-Success

Effect unsuccessfully executed

After an effect was unsuccessfully executed the error key contains the error.

State-Success

Form Store

interface Product {
  name: string;
}

@Component({
  selector: 'my-app-basic-app',
  templateUrl: 'persist-form.html',
})
export class PersistFormComponent implements OnDestroy {
  productForm = new FormGroup({
    name: new FormControl('', [Validators.required]),
    lastName: new FormControl('', [Validators.required]),
  });
  private store = this.storeFactory.createFormComponentStore<Product>({
    storeName: 'PRODUCT_FORM',
    plugins: {
      storage: 'sessionStoragePlugin',
    },
    formGroup: this.productForm,
  });
}

Session/Local Storage

Register Session/Locale storage service

  1. Register Session/Locale storage in your root module
@NgModule({
  // ...
  providers: [
    {provide: SessionStoragePlugin, useValue: sessionStoragePlugin},
    {provide: LocalStoragePlugin, useValue: localStoragePlugin}
  ]
  // ...
})
  1. Create new store with a session storage sync option
class MyClass {
  private store = this.storeFactory.createComponentStore<{ counter: number }>({
    storeName: 'SESSION_COUNTER',
    defaultState: {
      counter: 0,
    },
    plugins: {
      storage: 'sessionStoragePlugin',
    },
  });
}

Create Effects

For Using createEffect, please install @ngrx/effects and import EffectsModule.forRoot([]) in your root module

export const resetAction = createAction('reset');

class MyClass {
  private store = this.storeFactory.createComponentStore<{ counter: number }>({
    storeName: 'SESSION_COUNTER',
    defaultState: {
      counter: 0,
    },
  });

  myEffect = this.store.createEffect((action) =>
    action.pipe(
      ofType(resetAction),
      tap(() => console.log('do sth.')),
    ),
  );
}

Listen on actions

listen on custom actions to execute your business logic

export interface MyState {
  counter: number;
}
export const resetAction = createAction('reset');

@Injectable()
export class MyStore implements OnDestroy {
  private storeFactory = inject(StoreFactory);
  private store = this.storeFactory.createComponentStore<MyState>({
    storeName: 'BASIC_COUNTER',
    defaultState: { counter: 0 },
  });

  onReset = this.store.onActions([resetAction]);
}
export class AppComponent {
  private myStore = inject(MyStore);
  resetEffect = this.myStore.onReset(() => console.log('Reset was triggered'));
}

Testing

Import storeTestingFactory and write your tests. A minimal example can be found here .

TestBed.configureTestingModule({
  //...
  providers: [storeTestingFactory()],
  //..
});

ngrx-lite's People

Contributors

dependabot[bot] avatar gernsdorfer avatar schroedan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ngrx-lite's Issues

Create Store reducer If reducer is not created (for Timetravelling)

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Remove Store If devtool ist disabled

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Skip Logging for the complete Store, to avoid storing userdata

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.