Skip to content

Callback Heaven

Kenneth Tilton edited this page Apr 4, 2022 · 6 revisions

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.

lesson objectives

  1. learn how to use the mxXHR proxy Matrix type tiltontec.mxxhr.core/xhr;
  2. grok that async and reactive are made for each other; and
  3. get a first look at wrapping something (an XHR) so it can play with the other reactive kids.

background

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 at false and then mset! it to true when we like;
  • :response will 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 reactively read the :response, and change shape when it goes from nil to a response. For example:

(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))})

mission requirements

  • 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 have been reported that link to that word. 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.

writing the code

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:

  1. navigate to the input field and get its :value property;
  2. to get the widget me, this ^^^ must be done in a cF formulaic cell;
  3. if the input drug name value is not blank...
  4. ...create the proxy XHR from the supplied code.

Clone this wiki locally