Skip to content

Callback Heaven

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

We ourselves were surprised to discover that reactive state eliminates the problem of "Callback Hell". Yay. The cure comes in two steps:

  • the Matrix approach involves making everything reactive;
  • 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. Specifically, learn how to use the mxXHR proxy Matrix type tiltontec.mxxhr.core/xhr.

  2. In general, grok that async and reactive are made for each other.

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.

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:

    (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;
  • :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.

(h3 {:content (cF (when-let [ae-response (mget some-XHR :response)]
                    (if (= 200 (:status ae-response))
                      "Adverse Events Found"
                      "No adverse events reported to FDA")))})

Clone this wiki locally