UNPKG

ngrx-loading-state

Version:

NgRx Loading State consistently manages loading actions such as API fetches.

151 lines (150 loc) 7.72 kB
import { DefaultProjectorFn, MemoizedSelector } from '@ngrx/store'; import { Action, TypedAction } from '@ngrx/store/src/models'; import { catchError } from 'rxjs'; import { ActionFactoryResult, FailureAction, LoadAction, LoadingActionsReducerTypes, LoadingState, LoadingStates, OnState } from './loading-state-types'; /** * This class bundles up a set of load, success, and failure actions. It contains helpers to create * reducers for these actions and helpers for creating selectors. * * Do not use this class directly, use the createLoadingActions() helper function. * */ export declare class LoadingActions<LoadPayloadType extends object, SuccessPayloadType extends object, FailurePayloadType extends object> { /** The actions the user can dispatch */ readonly load: ActionFactoryResult<LoadAction & LoadPayloadType>; readonly success: ActionFactoryResult<SuccessPayloadType>; readonly failure: ActionFactoryResult<FailureAction & FailurePayloadType>; constructor(options: { load: ActionFactoryResult<LoadAction & LoadPayloadType>; success: ActionFactoryResult<SuccessPayloadType>; failure: ActionFactoryResult<FailureAction & FailurePayloadType>; }); /** * Type guard to test if action is of type LoadingActions.load. * * @param action Any ngrx action * @returns True if action if of type LoadingActions.load */ instanceOfLoad(action: Action): action is ReturnType<ActionFactoryResult<LoadAction & LoadPayloadType>>; /** * Type guard to test if action is of type LoadingActions.success. * * @param action Any ngrx action * @returns True if action if of type LoadingActions.success */ instanceOfSuccess(action: Action): action is ReturnType<ActionFactoryResult<SuccessPayloadType>>; /** * Type guard to test if action is of type LoadingActions.failure. * * @param action Any ngrx action * @returns True if action if of type LoadingActions.failure */ instanceOfFailure(action: Action): action is ReturnType<ActionFactoryResult<FailureAction & FailurePayloadType>>; /** * Creates reducers for the load, success, failure actions. * * @param options.onLoad Call back when action is LoadAction. Return new copy of state if state needs to change. * @param options.onSuccess Call back when action is SuccessAction. Return new copy of state if state needs to change. * @param options.onFailure Call back when action is FailureAction. Return new copy of state if state needs to change. * @returns A tuple of "on()" instances that handles load, success, failure actions in this order. * @example * export const reducer = createReducer( * initialState, * // Note: (1) * ...fetchItem.reducer<ItemState>({ * onSuccess: (state, { item }): ItemState => { * return { ...state, item }; * }, * // You can also customise what happens for LoadAction and FailureAction through onLoad and onFailure. * // But most of the time, there's nothing to do for those. They are automatically handled by the fetchItem.reducer * }), * ); * * (1) We need this explicit return type because "return type widening" means that the * type constraints on the onSuccess function is only narrowing, so if you provide more * fields in the return object that is not in VaultState, there is no error. Because * the return value can be narrowed to the onSuccess function's constraints. So we have * to explicitly specify the return type here. This is a well known issue that has been * raise since at least 2016. So does not look like it will be fixed. Also, it's a recommended * pattern in ngrx reducers to have this explicit typing. * * Ref https://github.com/microsoft/TypeScript/issues/241#issuecomment-327269994 * * (2): Given that there are explicity return types on the onLoad, onSuccess, onFailure functions * it should be possible to infer the type of the state here. But can't figure out how. * */ reducer<State extends { loadingStates: LoadingStates; }>(options?: { onLoad?: (state: OnState<State>, action: LoadAction & LoadPayloadType & TypedAction<string>) => State; onSuccess?: (state: OnState<State>, action: SuccessPayloadType & TypedAction<string>) => State; onFailure?: (state: OnState<State>, action: FailureAction & FailurePayloadType & TypedAction<string>) => State; }): [ LoadingActionsReducerTypes<State>, LoadingActionsReducerTypes<State>, LoadingActionsReducerTypes<State> ]; /** * Catches errors in effect. * * @returns rxjs operator that emits a FailureAction. * @example * * fetchCount$ = createEffect(() => { * return this.actions$.pipe( * ofType(fetchCount.load), * filterLoading(this.store.select(fetchCountSelectors.state)), * switchMap((action) => { * return apiCAll().pipe( * map(item => fetchCount.success(item)), * fetchCount.catchError() * ); * }) * ); * }); * */ catchError(): ReturnType<typeof catchError>; /** * Returns a map of selectors for loading, success, error, and the entire loading state. Similar to the ngrx entities adaptor. * * Design: The advantage of doing it in a bundle is that we can share the result of createStateSelector(). * If we had separate individual functions, each function might need to call createStateSelector() * to create a new instance of the selector. We can't cache any created selectors because that will cause * a memory leak since the cached references are always held in this class and hence does not get released. * * @param selectLoadingStates Selector that returns the loadingStats of the feature slice. You can use createLoadingStatesSelector() * to create it. * @returns A collection of selectors * state: the LoadingState * loading: True if loading * success: True if last load was successful * error: any errors from the last API call. * @example * // The feature slice selector. Standard ngrx stuff. * const selectState = createFeatureSelector<SimpleState>(SIMPLE_FEATURE_KEY); * * // Selector that selects the loadingStates field from the global store. The createLoadingStatesSelector() * // is provided as a part of this lib as well. * const selectLoadingStates = createLoadingStatesSelector(selectState); * * // Create the selectors related to the fetchItem loading state. * export const fetchItemSelectors = fetchItem.createSelectors(selectLoadingStates); * * // You can then observe the loading states: * this.store.select(fetchItemSelectors.state); // The entire LoadingState * this.store.select(fetchItemSelectors.success); // The boolean success flag * this.store.select(fetchItemSelectors.loading); // The boolean loading flag * */ createSelectors(selectLoadingStates: MemoizedSelector<object, LoadingStates, DefaultProjectorFn<LoadingStates>>): { state: MemoizedSelector<object, LoadingState, DefaultProjectorFn<LoadingState>>; loading: MemoizedSelector<object, boolean, DefaultProjectorFn<boolean>>; success: MemoizedSelector<object, boolean, DefaultProjectorFn<boolean>>; error: MemoizedSelector<object, any, DefaultProjectorFn<any>>; }; private get key(); private getLoadingState; private setState; }