Read and Delete Graphics
Create Reframe handlers to read and delete graphics. Analogous to GET and DELETE in a REST API.
Read and delete graphics#
Continuing the progress from the last chapter, we'll build the functionality to read and delete graphics from Firebase, again without the UI.
Read graphics#
Reading from Firebase is straightforward. We set up the read rules in the last chapter so we can jump straight to the Reframe loop.
Dispatch read event#
Just like we did for graphic creation, we can dispatch a read event in :a.p.g
namespace:
(rf/dispatch [:app.domain.firebase/fetch-graphics])
In the real world, you might want to paginate and filter the records you fetch from an API. The pagination and filter parameters can be passed as the next elements of the event vector: [:fetch-graphics "filter term" 1 4]
. But for our case, we'll fetch and show all graphics.
Read event handler#
The event handler's job is similar to the create
event handler. It starts a loading indicator and calls a custom effect to fetch the list of graphics:
(rf/reg-event-fx
::fetch-graphics
(fn [{:keys [db]} _]
{:db (assoc db ::fetching-graphics? true)
:firebase/read {:node (str "/graphics/" (-> db ::user :uid))
:on-success [::fetch-graphics-success]
:on-error []}}))
Notice how we passed an empty vector to :on-error
parameter. We haven't written the custom :firebase/read
effect yet, but when we do, we'll ensure that we handle empty :on-error
cases. This is useful because sometimes errors need not be handled.
Read effect handler#
The effect handler reads data from a node and passes it to the on-success
handler. It doesn't concern itself with the saving of data to app-db
. This is because the effect can be used to fetch any node, and not just the graphics node:
(rf/reg-fx
:firebase/read
(fn [{:keys [node on-success on-error]}]
(-> firebase
(.database)
(.ref node)
(.once "value")
(.then (fn [snapshot]
(rf/dispatch (conj on-success (-> snapshot
(.val)
(js->clj :keywordize-keys true))))))
(.catch (fn [error]
(when on-error
(rf/dispatch (conj on-error error))))))))
Items in Firebase DB can either be read once or every time the database changes. The latter is good for syncing between multiple clients. Since we are building with a single client, we will read the values just once.
A successful read returns a snapshot
object. This is the state of the requested node wrapped in a JS object. The method snapshot.val
returns the JSON value of the node.
We take the snapshot
's value, convert it to a Clojure from JSON, and dispatch the on-success
event with this value.
js->clj
converts JSON to Clojure map, :keywordize-keys
converts keys from string to keywords:
(js->clj (js/JSON.parse "{\"hello\": \"world\"}")) ;; => {"hello" "world"}
(js->clj (js/JSON.parse "{\"hello\": \"world\"}") :keywordize-keys true) ;; => {:hello "world"}
Finally, in the .catch
block, we check if an on-error
event is available, and if so we dispatch the error. The error
here is a JavaScript object and can be inspected using js/console.log
.
Fetch success read handler#
When the fetch is successful, the effect dispatches the event defined in on-success
with the fetched records. We now need to handle this event and save the fetched data in app-db
:
(rf/reg-event-db
::fetch-graphics-success
(fn [db [_ graphics]]
(-> db
(dissoc ::fetching-graphics?)
(assoc ::graphics graphics))))
We use reg-event-db
because we only need the db
co-effect. The handler removes the loading status using dissoc
and sets ::graphics
in the app-db
using assoc
.
When the loop is complete, all graphics will be present in app-db
at ::graphics
(ie. :a.d.f/graphics
). The graphics in app-db
is a Clojure map, where keys are the unique ids of all graphics and values are the associated JSON.
This page is a preview of Tinycanva: Clojure for React Developers