1.1.0 • Published 3 months ago

@ngrxs/states v1.1.0

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

@ngrxs/states

@ngrxs/states library that provide a common state objects that include selecting, loading and saving metadata.

Installation

npm peer dependency @ngrx/store version

  1. npm install --save @ngrxs/states
  2. Import and use SharedState in a state:

    import { SharedState, adapter } from '@ngrxs/states';
    
    export type UsersState = SharedState<Users[], number>;
    export const initialState: UsersState = adapter.getInitialState<User[], number>([]);

Usage

@ngrxs/states provides shared state to hold loaded, loading, saving information and selectors for it.

// filename: users.reducer.ts

import { adapter, SharedState } from '@ngrxs/states';
import { createReducer, on } from '@ngrx/store';

import * as actions from './users.actions';
import { User } from '../models/user';

export type UsersState = SharedState<User[], number>;

export const initialState: UsersState = adapter.getInitialState<User[], number>([]);
export const setUser = adapter.createArraySetter((user: User) => user.id);

export const usersReducer = createReducer(
  initialState,
  on(actions.getAllUsers, state => adapter.loading(state, state.entities)),
  on(actions.allUsersLoaded, (state, { users }) => adapter.loaded(state, users)),
  on(actions.allUsersLoadFail, (state, { error }) => adapter.loadFail(state, error)),
  on(actions.editUser, state => adapter.saving(state)),
  on(actions.editUserSuccess, (state, { user }) => adapter.saved(state, setUser(state, user))),
  on(actions.editUserFailed, (state, { error }) => adapter.saveFail(state, error))
);

adapter Methods

adapter.getInitialLoadableState<T>(value: T)

{
  entities: value,
  loading: {
    error: null,
    loading: false
  },
  loaded: false
}

adapter.getInitialState<T>(value: T)

{
  entities: value,
  loading: {
    error: null,
    loading: false
  },
  loaded: false,
  saving: {
    error: null,
    loading: false
  },
  selectedId: null
}

adapter.select(state: TState, selectedId: TId) => ({ ...state, selectedId })

adapter.loading(state: TState, entities: TData) => ({ ...state, entities, loading: { loading: true, error: null } })

adapter.loaded(state: TState, entities: TData) => ({ ...state, entities, loading: { loading: false, error: null }, loaded: true })

List of Selectors

SelectorsUsage
selectEntitiesSelect the state entities
selectSaveStateSelect the saving state
selectLoadStateSelect the loading state
selectLoadedSelect the loaded value
selectSelectedIdSelect the selected id

Interfaces

@ngrxs/states exposes interfaces.

LoadableState

{
  error: string | null;
  loading: boolean;
}

SharedLoadableState<TData>

{
  readonly entities: TData;
  readonly loading: LoadableState;
  readonly loaded: boolean;
}

SharedState<TData, TId extends number | string | null>

{
  readonly entities: TData;
  readonly loading: LoadableState;
  readonly loaded: boolean;
  readonly saving: LoadableState;
  readonly selectedId: TId;
}

fetch method

a method fetch fetching state data from service.

fetch(options: {
  id?: (action: TAction) => PropertyKey          // (optional) get the unique id to group results.
  ttl?: number                                   // (optional) when provided it caches the result. ttl is in milliseconds.
  fetch: (action: TAction) => Observable<TData>; // the fetch action
  mapFn: (data: TData) => Action;                // the action mapper function
  errorFn: (error: Error) => Action;             // the error mapper function
})

Example

import { fetch } from '@ngrxs/states';

@Injectable()
export class UsersEffects {
  readonly #actions$ = inject(Actions);
  readonly #service = inject(UsersService);
  
  loadUsers$ = createEffect(() =>
    this.#actions$.pipe(
      ofType(actions.getAllUsers),
      fetch({
        fetch: () => this.#service.getAllUsers(),
        mapFn: payload => actions.allUsersLoaded({ users: payload }),
        errorFn: error => actions.allUsersLoadFail({ error }),
      })
    )
  );

  getUserById$ = createEffect(() =>
    this.#actions$.pipe(
      ofType(actions.getByUserId),
      fetch({
        id: ({ id }) => `user_${id}`,
        ttl: 5_000,
        fetch: ({ id }) => this.#service.getUserById(id),
        mapFn: user => actions.userLoaded({ user }),
        errorFn: error => actions.userLoadFail({ error }),
      })
    )
  );
}
1.1.0

3 months ago

1.0.0

7 months ago

0.0.1

7 months ago