A bit late to the party. But Jon's post is still at the top of google searches so obviously still quite relevant. We've faced the same issues and also the need to display loading states at a component level. We've elected to go with loading at the component level because it's the most fine grained approach.
The most important consideration is that the loading states should be tied to the ngrx action, not the data it actually loads because different actions could load overlapping pieces of data.
The biggest pain it solves for use is we can issue loading actions without needing to think about whether the data has already been loaded, i.e. a well behaved cache.
The fetchRecordState contains a much of other states related to the API call:
{loading:boolean;// Api is loadingsuccess:boolean;// Api returned successfullyissueFetch:boolean;// true if we should issue a fetcherrorHandler:LoadingErrorHandler;successTimestamp?:number;// Millisecond unix timestamp of when data is loaded. Date.now()error?:LrError2;// Api returned error}
Loading actions are bundled to reduce boiler plate:
exportconstfetchRecord=createLoadingActions(`[${NAMESPACE}] Fetch Record`,load<{recordId:string}>(),success<{record:Record}>()// failure action is automatically created.);
Effects handles the maxAge caching behaviour:
fetchRecord$=createEffect(()=>{returnthis.actions$.pipe(ofType(VaultActions.fetchRecord.load),// This handles the maxAge caching behaviourLoadingStatesManager.filterLoading(this.store.select(fetchRecordSelectors.state)),switchMap((action)=>{returnthis.vaultService.fetchRecord(action.recordId).pipe(map((records)=>{returnVaultActions.fetchRecord.success({record});}),VaultActions.fetchRecord.catchError());}));});
If there is interest, we'll put up an NPM package for it and we can explore togather.
A bit late to the party. But Jon's post is still at the top of google searches so obviously still quite relevant. We've faced the same issues and also the need to display loading states at a component level. We've elected to go with loading at the component level because it's the most fine grained approach.
The most important consideration is that the loading states should be tied to the ngrx action, not the data it actually loads because different actions could load overlapping pieces of data.
The biggest pain it solves for use is we can issue loading actions without needing to think about whether the data has already been loaded, i.e. a well behaved cache.
It sits strictly on-top of
ngrx
, no hidden magic.A typical component looks like:
The
maxAge
tells us it's ok to not load if the last load is less than 5000ms old. @michaelkariv you might be interested in this.Template can display the loading state as such:
The
fetchRecordState
contains a much of other states related to the API call:Loading actions are bundled to reduce boiler plate:
Effects handles the
maxAge
caching behaviour:If there is interest, we'll put up an NPM package for it and we can explore togather.
Here's the lib: github.com/amzhang/ngrx-loading-state