Use indexedDb with ngrx for fast angular bootstrap
At whoz.com, we have an intensive use of ngrx. We paired it with indexedDb to load a massive initial state in a snap.
We find ngrx so great and so useful, that we’ve put most of the data handling in the angular frontend, and rely on the spring cloud backend for security, long term persistence and sensitive business logic.
This means that we load a bunch of data at application bootstrap. We wanted to store the last known state on the client side to allow for fast bootstraps after the very first load of the app. A first prototype with localStorage worked great until we reached the dreaded 10MB limit in chrome.
That’s where it became interesting because:
- indexedDb could hold a virtually infinite amount of data :-)
- indexedDb is asynchronous :-|
- ngrx initialization and reducers are not :-(
Here is what we did, note that it also relies on your reducers being a bit smarter than the pure functions they are. You can read about how we use injected services in reducers.
Angular provides a way to execute code before the app initialization by providing functions to the APP_INITIALIZER multi provider. When those functions return promises, the app initialization is put on hold until they are all resolved.
In the promise we’ll access our asynchronous storage and temporarily store our initial state to give it to ngrx later.
Then when the promises are resolved (ie. all initial slices of state have been read from indexedDb) we trigger our own AppInitAction. You can know about app initialization via the angular ApplicationInitStatus.
At last you can listen for this action in your reducer to provide the initial state that you previously stored for synchronous access.
To sum it up, you can have an asynchronous initial state in ngrx by:
- loading this initial state in APP_INITIALIZER promises
- storing this state for later synchronous access by ngrx
- triggering your own AppInitAction when ApplicationInitStatus.donePromise is resolved
- listening for this action in your reducer to use the previously stored initial state
It would be much easier if ngrx allowed for an asynchronous initial state factory, watch for this issue where it may happen, and until them I hope this helped :-)