From a high level of view, how can I integrate IndexDB in a re-frame single page mobile web app?
The app is a simple wizard with a lot of input fields, included several image upload. The different FileList objects of these photos are stored in re-frame’s app-db, so I can use something like GetObjecturl to show thumbnails. This wizard will be used by technicians, sometimes on places (factories) with limited internet connection. I want to prevent the wizard from losing all data of the inputs and photos.
So I am thinking to regularly make a backup of re-frame’s app-db into IndexedDB. What are the possible strategies? I was thinking something that runs every x seconds and then make a backup. Or should each event, next to updating the db, also update the IndexedDb? Wouldn’t that be slow?
Thanks in advance
Or maybe another solution is to save the appdb every x seconds.
Each event that updates the app-db (like typing in an input field) also fires an event “schedule-post-data”. And that event calls js/setTimeout with x seconds timeout and of course first clearing the previous timeout. So while typing, all lot of schedule-post-data will be called. But the actual post to server would only be executed once, after x seconds.
Maybe to get some inspiration, there’s a way to get your state in localStorage. (I think getting it to indexedDB should be comparable)
What I do to get this effect, is use handler middleware I apply to some handlers that just save the complete state or a subset of it
ie. use a re-frame middleware like:
(def local-storage-persist-interceptor (re-frame.core/->interceptor :id :system.local-storage/interceptor :after (fn [context] (persist-db-to-local-storage (:db (:effects context))) context)))
Thanks simongray, I’ll have a look at it.
Thanks for the info Kah0ona. What about events attached to onChange of a text input? Wouldn’t they trigger a lot of persist-db-to-local-storage? Like after each character is typed in the input field.
EDIT : after looking into the source of storage-atom I found out it has some nice debounce and delay functionality which solves my problem
There is a very popular JS library called localForage, which has a local-storage-like API for interacting with IndexedDB. You can easily interop with it from CLJS. Also, instead of updating the state on every on-change event, it may be better to update when the input has been blurred / loses focus (i.e. via the on-blur event).
yes, but, you can apply middleware on SOME handlers.
(rf/reg-event-db ::my-handler [my-persisting-middleware] (fn [db _] ,,,))
So use that tactically.
And yes, that storage atom lib does some clever stuff; but I prefer to have a bit of control when to persist.