-
Notifications
You must be signed in to change notification settings - Fork 0
Callback Heaven
We ourselves were surprised to discover that reactive state eliminates the problem of "Callback Hell". Yay. The cure comes in three steps:
- in general, the Matrix "all-in" approach works by making everything reactive;
- specifically, we make a reactive proxy XHR for any XHR we want to make; and
- the async response to a real XHR then becomes just another external state arrival, like a GUI user's mouse click.
Let us get to the mission.
- learn how to use the mxXHR proxy Matrix type
tiltontec.mxxhr.core/xhr; - grok that async and reactive are made for each other; and
- get a first look at wrapping something (an XHR) so it can play with the other reactive kids.
We have already seen that Matrix model properties can be reactive "inputs", meaning they can accept new state from outside the overall matrix tree. It cannot be formulas all the way down.
We also understand that any formulaic Cell that simply reads an input Cell will be re-run automatically when the input cell changes.
This turns out to solve async programming trivially, as long as we can take standard XHRs and teach them to be reactive. This brings us to the most important skill a Matrix programmer develops: wrapping un-reactive things in new Matrix model types that are reactive.
The good news for this mission is that Matrix includes a serviceable XHR proxy we call mxXHR. Somewhat simplified:
(defn make-xhr [uri body-parser send?]
(apply make
:type :tiltontec.mxxhr.core/xhr
:uri uri
:send? (cI send?)
:response (cI nil)
:body-parser (or body-parser
#(#?(:clj parse-json$ :cljs identity) %))))
That creates the proxy XHR. Note the two cI input properties:
-
:send?is an input in case we want to defer sending the XHR. Then we would start it atfalseand, when ready to do the lookup,mset!it totrue; -
:responsewill be set by the actual XHR handler when the response or error is returned;
A reactive observer on the :send? property takes care of actually sending the XHR:
(defmethod observe [:send? :tiltontec.mxxhr.core/xhr] [_ me newv _ _]
(when newv
(xhr-send me)))
Now the rest of the reactive Matrix can read the :response and, when it goes from nil to a response, react accordingly. For example, with a single component both generating the XHR and reacting to it:
(h3 {:content (cF (when-let [ae-response (mget (mget me :lookup) :response)]
(if (= 200 (:status ae-response))
"Adverse Events Found"
"No adverse events reported to FDA")))}
{:lookup (cF (make-xhr etc etc))})
- When the user enters a word, by pressing Enter or navigating away, look the word up on the OpenFDA Adverse Events database to see if any AEs linked to that word have been reported. Almost everything, by the way, returns "hits";
- if no hits are returned, say so;
- if hits are returned, list them.
We will provide a bunch of code so you can just think about Matrix, not the OpenFDA API.
The starting source for this mission is in m022-callback-heaven.
Look for "Your code here #1". Here, you need to use the suggested code to make a reactive XHR proxy to look up whatever the user entered and bind that to the :ae-lookup property. The remaining work for you:
- navigate to the input field and get its
:valueproperty; - to get the widget
me, this ^^^ must be done in acFformulaic cell; - if the input drug name value is not blank...
- ...create the proxy XHR from the supplied code.
Now look for "Your code here #2". That section is heavily commented, and even includes the code to navigate to the component holding the XHR as the property :ae-lookup. You just need to build the HTML/CSS to display the three cases:
- lookup not yet sent;
- lookup sent but response not received; and
- lookup sent and response received, with or without AEs.
Again, please follow the copious comments to complete this mission, using the helper utilities documented.
Help learning mxWeb is available on the #matrix channel of Clojurians Slack.
Issues with this trainer can be reported on its GitHub repo.