-
Notifications
You must be signed in to change notification settings - Fork 0
Simulating Effects
- Effect functions
Our application is now receiving input from the outside world. In this section we will make it effect the outside world by allowing it to send its counter value to a service.
To accomplish this we will add an effect function to the dataflow.
Effect functions generate messages which will be sent out from the
application. This function will be added to the
tutorial-client.behavior namespace.
The exact arguments to an effect function will depend on how that
function is configured. Effect functions always return a sequence of
messages to send. This function will take a counter value as an
argument.
(defn publish-counter [count]
[{msg/type :swap msg/topic [:other-counters] :value count}])The returned message is similar to the message above which is used to
set the value of the other counters. When this message arrives at the
service, the session id will be added to the topic before the
message is forwarded to the other clients.
To add this function to the dataflow, we add an :effect key. Effects
are configured as a set of vectors. Each vector has three elements, a
set of inputs, the effect function and the arguments specification.
:effect #{[#{[:my-counter]} publish-counter :single-val]}The arguments specification indicates that the function should be
passed a single value which will be the value at :my-counter in the
data model. For more information on argument specifiers, see [[Derived
Values]].
This configuration will cause the publish-counter function to be
called whenever the value at :my-counter changes.
The complete dataflow definition now looks like the one shown below.
(def example-app
{:version 2
:transform [[:inc [:my-counter] inc-transform]
[:swap [:**] swap-transform]]
:effect #{[#{[:my-counter]} publish-counter :single-val]}
:emit [{:init init-main}
[#{[:my-counter] [:other-counters :*]} (app/default-emitter [:main])]]})What happens to effects after they are generated? Effect messages
are put on a queue and can be consumed by a service. Our simulated
service will handle these messages by printing them to the JavaScript
console.
In the tutorial-client.simulated.services namespace, add the following
function which will be used to process outgoing messages. In the real
service, this function would send the message over the network to a
back-end service.
(defn services-fn [message input-queue]
(.log js/console (str "Sending message to server: " message)))The handler function receives the message and the input-queue. The
input-queue is used to allow callbacks to send results back to the
application. Here it is ignored.
Back in the tutorial-client.simulated.start namespace we need to
arrange for every message placed on the effect queue to be processed
by this handler function.
First we require the io.pedestal.app namespace.
[io.pedestal.app :as app]Then we use the consume-effects function to set this up.
(app/consume-effects (:app app) services/services-fn)The main function should now look like the one shown below.
(defn ^:export main []
(let [app (start/create-app d/data-renderer-config)
services (services/->MockServices (:app app))]
(app/consume-effects (:app app) services/services-fn)
(p/start services)
app))To test that this works, refresh the page and then open the JavaScript console and click on the Increment Counter button. You should see the message printed in the console.
This simple application now has some basic values and can send and
receive messages. The next section will introduce dataflow in a bit
more detail as we look at how to use derive functions to generate
new values.
The tag for this step is v2.0.5.