Fork me on GitHub
#re-frame
<
2017-01-31
>
michael.heuberger02:01:07

re-frame guys, is there a good example out there how to test event handlers and subscribers?

emccue02:01:19

Perhaps you can tell where you are having issues testing them specifically, but the easiest solution for non cofx handlers and subscriptions is just to separate the definition of the function and the declaration of it as a handler

emccue02:01:05

So (reg-event-db :something handler)

emccue02:01:48

(defn handler [db args] ... return new db ...)

emccue02:01:01

Then just test it like any other function, feeding it inputs that match possible app states and what you accept as data for the event

emccue02:01:55

That's neat; I'll earmark it

escherize02:01:31

its possible to test the handlers and subscriptions from the JVM using that.

escherize02:01:37

runs pretty fast

scknkkrer08:01:54

Guys, I have a beginner question; Is it possible to develop a migratable project with no changes. React and web.

heeton09:01:33

@scknkkrer Can you rephrase that question? Not sure what you mean

smogg09:01:28

I have a question about view-related data, e.g. dynamic class names. Let’s say I have a list of todos, some of them are done, some of them are not. Based on their donness I want to apply a CSS class - either a class of todo-completed when an item is done or just todo otherwise. My todo-item view subscribes to a subscription, gets item’s data back - the piece of that data that we care about is a boolean done? based on which I can create a class name: (if done? “todo-completed” “todo”). My question is - should this small if-statement live as a separate subscription providing a string to be used as css-class back to the view or should I just use it directly in my view? used directly:

(defn todo-item
 [id]
 (let [{:keys [done?]} @(re-frame/subscribe [:todo-item id])
       item-class (if done? "todo-completed" "todo")]
  [:div {:class item-class}
   "Hello, I'm a todo-item"]))
subsciption returining a class name:
(defn todo-item
 [id]
 (let [item-class @(re-frame/subscribe [:todo-item-class id])]
  [:div {:class item-class}
   "Hello, I'm a todo-item"]))
Subscribing for stuff like class names and other markup attrs will greatly increase number of subs as my app grows. At the same time, this class name is not necessarily a part of the global state - it is part of this particular view - so maybe I should keep it this way?

mikethompson10:01:46

@smogg I think you'd use the first approach

mikethompson10:01:20

obtain done? via the subscription, and then use it to compute the class

mikethompson10:01:00

In my world, the view function should compute everything to do with the visual representation - the hiccup, the classes, etc. A subscription is like a database query. Obtaining the data needed.

mikethompson10:01:44

So :done? is "needed data" ... that is produced by the subscription But the class is part of the view's computations. The view knows about CSS etc. It knows how to use :done? to deliver the right visual representation

smogg10:01:05

yeah, that makes sense - thanks @mikethompson

akiroz14:01:08

Got a question about the order of events and views: I have an event that updates some data which updates the DOM, that event also dispatches another event that reads changes off the DOM. Is there anyway to ensure that the second event is ran after all the subs and views? My current workaround is to use a :dispatch-later with a small delay to ensure the second event is schedueled last but is there a better way to handle this?

ckirkendall16:01:21

@akiroz can you give an example of what you trying to do with this type of behavior? Maybe a use case? In general, items that need to read the DOM after a render are part of the did-update lifecycle event on the component involved.

akiroz16:01:03

@ckirkendall the first event updates stuff on a canvas, the second one saves a jpeg from the canvas if certain conditions are met and uploads it to the server.

ckirkendall16:01:36

ok wrap the canvas in a reagent component that listens fires the event to check and save in the did-mount and did-update lifecycle events.

ckirkendall16:01:05

that way the event is only ever fired when the canvas renders

akiroz16:01:37

well actually, I have multiple canvases and I need to save an image of those canvases concatenated horizontally...

ckirkendall16:01:29

I would dispatch on each render of any of the three and the handler can use a debounced function to make sure multiple calls don’t cause issues.

ckirkendall16:01:50

You loose the purity of the handler but it provides a clean structure for dispatch

akiroz16:01:20

hmm, that sounds like a pretty good solution~ I wonder if we should support event debouncing in re-frame....

ckirkendall16:01:42

In my setup I have an interceptor that I can debounce dispatch to

ckirkendall16:01:55

I think debounce dispatch would be awesome as a core feature.

akiroz16:01:25

oh cool~ mind sharing your debounce interceptor?

ckirkendall16:01:52

I need to check with my client but I suspect I can.

akiroz16:01:31

thanks~ 🙂

ckirkendall17:01:28

Note: I had to remove some stuff around transaction tracking so it is possible I introduced bugs.

ckirkendall17:01:18

@akiroz - one of my friends mentioned it might be better to have this structure for :debounce vs the nested vectors like I show above. [{:event [:event-id arg1 arg2] :timeout 100} {:event [:event-id2 a2 a3] :timeout 200}]

mattsfrey17:01:13

Hey, was hoping to use re-frame's async-flow-fx to coordinate a workflow without using promises. Wondering if the expected behavior for doing a [{:when :seen? :events [:event-1 :event2] :dispatch [:do-finish]} would be to wait until both event-1 and event-2 have fired and then fire do-finish?

mattsfrey17:01:30

nvm just noticed :seen-all-of? sry

akiroz18:01:31

@ckirkendall Awesome, thanks for all the help~ 🙂