3.1.3 • Published 11 months ago

@ngneat/effects-ng v3.1.3

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

A framework-agnostic RxJS effects implementation

@ngneat/effects commitizen PRs coc-badge semantic-release styled with prettier

Effects

First, we need to initialize the the library by calling the initEffects() function:

import { initEffects } from '@ngneat/effects';

initEffects();

Actions are created by using the createAction or actionsFactory functions:

import { actionsFactory, createAction, props } from '@ngneat/effects';

// todos.actions.ts
export interface Todo {
  id: string;
  name: string;
}

export const addTodo = createAction('[Todos] Add Todo', props<{ title: string });

// Ee recommend using the actions factory to prefix each action 
// for better readability and debug purposes when using redux dev tools
export const todoActions = actionsFactory('todo');

// We can declare an action by passing it a type and an optional payload. 
export const loadTodos = todoActions.create('Load Todos')
export const addTodo   = todoActions.create('Add Todo', props<Todo>())

Next, we need to define the effects, and register them:

import { createEffect, registerEffects, ofType } from '@ngneat/effects';

export const addTodo$ = createEffect((actions) =>
  actions.pipe(
    ofType(addTodo),
    tap(console.log)
  )
);

registerEffects([addTodo$])

Finally, we can dispatch actions using the dispatch function:

import { dispatch } from '@ngneat/effects';

dispatch(addTodo({ title: 'effects' }));

Use with React

First, install the package: npm i @ngneat/effects-hook.

Now, we can use the useEffects hook and pass our effects:

import { useEffects } from '@ngneat/effects-hook';
import { dispatch }   from '@ngneat/effects';
import { useEffect }  from 'react';

export function TodosPage() {
  useEffects([loadTodos$, addTodo$]);

  useEffect(() => dispatch(loadTodos()), []);

  return (
    <button onClick = {() => dispatch(addTodo({ title: 'foo' }))}>
      Add
    </button>
  )
}

The effects we pass are tied to the component life cycle hook and will be destroyed with the component.

Use with Angular

First, install the package: npm i @ngneat/effects-ng.

Next, create the effect provider:

import { createEffect }  from '@ngneat/effects';

@Injectable({ providedIn: 'root' })
export class TodosEffects {

  constructor(private todosApi: TodosApi) {}

  loadTodos$ = createEffect(actions => 
    actions.pipe(
     ofType(loadTodos),
     switchMap((todo) => this.todosApi.loadTodos())
    )
  );
}

Then we need to register our the effects in our app module:

import { EffectsNgModule } from '@ngneat/effects-ng';
import { TodosEffects } from 'todos/todos.effect.ts';

@NgModule({
  imports: [
    EffectsNgModule.forRoot([TodosEffects]),
  ]
})
export class AppModule {
}

In order to register lazily loaded effects use the forFeature method:

import { EffectsNgModule } from '@ngneat/effects-ng';
import { PostsEffects } from "posts/posts.effect.ts"

@NgModule({
  imports: [
    EffectsNgModule.forFeature([PostsEffects])
  ]
})
export class LazyModule {
}

The actions can be dispatched by injecting the Actions provider:

import { Actions } from '@ngneat/effects-ng';

@Component(...)
export class AppComponent {
  constructor(private actions: Actions) {}

  ngOnInit() {
    this.actions.dispatch(loadTodos());
  }
}

Effect Functions

To use an effect function we first need to create it by using the createEffectFn function:

import { createEffectFn } from '@ngneat/effects';

export const searchTodoEffect = createEffectFn((searchTerm$: Observable<string>) => {
  return searchTerm$.pipe(
    debounceTime(300),
    switchMap((searchTerm) => fetchTodos({ searchTerm })),
  );
});

The createEffectFn function takes a callback function which is passed an Observable parameter and returns an Observable.

Use with React

First, install the package: npm i @ngneat/effects-hook.

We can register the effect in our component, and call it when we need:

import { useEffectFn } from '@ngneat/effects-hooks';

function SearchComponent() {
  const searchTodo = useEffectFn(searchTodoEffect);

  return <input onChange = {({ target: { value } }) => searchTodo(value) }/>
}

Every time the effect is called, its value is pushed into that Observable.

We can also register multiple effects:

function FooComponent() {
  const [addTodo, updateTodo, deleteTodo] = useEffectFn([
    addTodoEffect, updateTodoEffect, deleteTodoEffect
  ]);

  return ...
}

First, install the package: npm i @ngneat/effects-ng.

Create an effect class, extends the EffectFn class and use the createEffectFn method to create your effects:

import { EffectFn } from '@ngneat/effects-ng';

export class TodosEffects extends EffectFn {

  searchTodo = this.createEffectFn((searchTerm$: Observable<string>) => {
    return searchTerm$.pipe(
      debounceTime(300),
      switchMap((searchTerm) => fetchTodos({ searchTerm })),
    );
  });
}

Inject the effects provider in your component, and call it when you need:

@Component({
  providers: [TodosEffects],
})
export class TodosComponent {
  constructor(private todosEffects: TodosEffects) {
  }

  ngOnInit() {
    this.control.valueChanges.subscribe(searchTerm => {
      this.todosEffects.searchTodo(searchTerm);
    });
  }
}