   (let [binding-fns (r/get-binding-fns ref)
         deref* (.-deref binding-fns)
         add-watch* (.-add-watch binding-fns)
-        remove-watch* (.-remove-watch binding-fns)]
+        remove-watch* (.-remove-watch binding-fns)
+        ref-meta (meta ref)]
     (when (and add-watch* remove-watch*)
-      (let [attr-state #js {:disposed false}
-            key (r/new-reactive-id)
+      (let [key (r/new-reactive-id)
+            attr-state #js {:disposed false
+                            :disposed-callback
+                            (fn []
+                              (remove-watch* ref key)
+                              (when-let [binding-disposed (get ref-meta :binding-disposed)]
+                                (binding-disposed)))}
             invalidate
             (fn on-value-ref-invalidated
               ([]

                  (when-not (.-disposed attr-state)
                    (add-watch* ref key on-value-ref-invalidated)
                    (set-fn (non-reactively (deref* ref))))))))]
        (register-with-parent-state node-state
                                    (str "-" state-prefix "." attr-name) attr-state)
        (add-watch* ref key invalidate)))
    (set-fn (deref* ref))))


(defn- text-node? [dom-node]
  (identical? (.-nodeType dom-node) 3))

(def enable-diffing true)

(defn- register-element-with-parent [parent new-elem]
  (when-not (text-node? new-elem)
