Interacting With A View
Artemis should work just fine with any view library. We’ll first use plain-ol’ ClojureScript to render to the DOM, then we’ll show an example of how you might integrate with a reactive view library like Reagent.
Let’s start with some familiar code, then add in some view functions that use the goog.dom
namespace.
(ns app.core
(:require-macros [cljs.core.async.macros :refer [go go-loop]])
(:require [artemis.core :as a]
[artemis.document :refer [parse-document]]
[artemis.network-steps.http :as http]
[artemis.stores.mapgraph.core :as mgs]
[goog.dom :as goog-dom]))
;;; Set-up
(def graphcool-url "https://api.graph.cool/simple/v1/cjjh9nmy118fs0127i5t71oxe")
(def network-chain (http/create-network-step graphcool-url))
(def store (mgs/create-store))
(def client (a/create-client :network-chain network-chain
:store store))
;;; View
(defn show-loading! []
(let [loading (goog-dom/createDom "em" nil "Loading...")
app (goog-dom/getElement "app")]
(goog-dom/removeChildren app)
(goog-dom/appendChild app loading)))
(defn show-jerry! [jerry]
(let [jerry-name (goog-dom/createDom "h1" nil (:name jerry))
app (goog-dom/getElement "app")]
(goog-dom/removeChildren app)
(goog-dom/appendChild app jerry-name)))
;;; Query
(def get-jerry-doc
(parse-document
"query getJerry {
User(id: \"cjjh9x0q97x7r0111osr3t352\") {
id
name
}
}"))
(defn get-jerry []
(let [get-jerry-chan (a/query! client get-jerry-doc :fetch-policy :remote-only)]
(go-loop []
(when-let [x (<! get-jerry-chan)]
(if (:in-flight? x)
(show-loading!)
(show-jerry! (:User (:data x))))
(recur)))))
;;; Main
(defn main ^:export []
(get-jerry))
If you open up your browser, you should see some text rendered. Hopefully this barebones example shows you how you can integrate Artemis with any approach to rendering views. A more realisic, or at least common, example might include React. Let’s try the same example, but replace goog.dom
with Reagent, a ClojureScript interface for React.
First, install and require the latest version of Reagen. Then, let’s start by replacing our view and query code with the following:
;;; View
(defonce app-state (r/atom {}))
(defn loading []
[:em "Loading..."])
(defn jerry [jerry]
[:h1 (:name jerry)])
(defn app []
(if (:loading? @app-state)
[loading]
[jerry (:jerry @app-state)]))
;;; Query
(def get-jerry-doc
(parse-document
"query getJerry {
User(id: \"cjjh9x0q97x7r0111osr3t352\") {
id
name
}
}"))
(defn get-jerry []
(let [get-jerry-chan (a/query! client get-jerry-doc :fetch-policy :remote-only)]
(go-loop []
(when-let [x (<! get-jerry-chan)]
(reset! app-state {:loading? (:in-flight? x)
:jerry (get-in x [:data :User])})
(recur)))))
Finally, add a section that mounts our React application:
;;; Main
(defn mount []
(r/render [app] (.getElementById js/document "app")))
(defn main ^:export []
(get-jerry)
(mount))
Refresh your browser and you should get the same results, but this time going through Reagent. Of course, this is a trivial example, but go ahead and try expanding on this code. You might even consider swapping Reagent for Rum, or sticking with Reagent, but adding-in re-frame. Either case should be fairly easy because within or go-loop
we can manage our app-state however we’d like.