Skip to content

Beware Returning False

Mike Thompson edited this page Sep 16, 2015 · 7 revisions

Beware Of DOM Event Handlers Returning False

There is a trap when writing DOM event handlers. Notice we are talking here about DOM event handlers, not re-frame event handlers. So this page is about reagent, not really about re-frame (except for the bit at the end).

This code looks innocent enough:

  :on-mouse-out  #(reset! my-over-atom false)

But notice that it inadvertently returns false, and returning false means something:

  • v0.11 of React will invoke both stopPropagation() and preventDefault() on the event. Almost certainly not what you want.

  • v0.12 of React will do the same as v0.11, except it also issues a deprecation warning about false returns.

  • v0.13 of React will not interpret a false return at all.

Note: v0.11 and v0.12 of React only test explicitly for false, not falsy values. So 'nil' is a safe return value.

Solution

Below, 'handler-fn' is a macro which will stop you from inadvertently returning false in a handler.

(defmacro handler-fn
  ([& body]
    `(fn [~'event] ~@body nil)))  ;; force return nil

Usage Examples:

  :on-mouse-out  (handler-fn (reset! over-atom false))
  :on-mouse-out  (handler-fn
                    (reset! over-atom false)   ;; notice: no need for a 'do'
                    (now do something else)
                    (.preventDefault event))   ;; notice access to the 'event'

##Summary

There are two issues to keep in mind:

  1. If you accidently return false in v0.11 and v0.12 you'll get an unexpected outcome (event cancellation and stopPropagation). This can be a baffling bug, and its an easy trap to fall into. Use the macro above.
  2. if you deliberately return false to cause event cancellation and stopPropagation(), be aware that it won't work in v0.13.

React code of interest: https://github.com/facebook/react/blob/0.12-stable/src/browser/eventPlugins/SimpleEventPlugin.js#L314-L317

Update: it turns out that v0.13 is the same as v0.12. No change. However, v0.14 does appear to be rewritten and will not interpret a false return at all.

Dispatch Is Already Safe

Re-frame's dispatch returns nil, making it safe to use unwrapped by handler-fn.

This is okay:

:on-mouse-out  #(dispatch [:something])