omcljs / om

ClojureScript interface to Facebook's React
6.65k stars 364 forks source link

Lifecycle methods not called properly with multimethods #95

Closed katox closed 10 years ago

katox commented 10 years ago

It seems that if the multimethod indirection is used, component's lifecycle methods are not called.

  (defn test-view1 [app owner]
  (reify
    om/IWillMount
    (will-mount [_]
      (.log js/console "will-mount test")
      (om/set-state! owner :test :hoho))

    om/IDidMount
    (did-mount [_ _]
      (.log js/console "did mount test")
      (om/set-state! owner :test :hoho))

    om/IRenderState
    (render-state [_ {:keys [comm] :as state}]
      (.log js/console "render test state=" (pr-str state))
      (dom/div #js {:onClick #(put! comm [:switch-to test-view2])} (str "oh " (:test state))))))

Let's say we are altering test-view1 (and similar test-view2). if called via multimethods, the same way as in the Om tutorial, then will-mount and did-mount methods are skipped (render-state work normally).

This doesn't work properly:

(defmulti test-view (fn [{:keys [cond]} _]  (if cond :test1 :test2)))
(defmethod test-view :test1
  [data owner] (test-view1 data owner))
(defmethod test-view :test2
  [data owner] (test-view2 data owner))

  (om/build-all test-view
                             all-data
                             {:key :id
                              :init-state {:comm comm :test :shouldnt-be-here}})

If changed from multimethods to a switch it does work normally (lifecycle methods call for view1 and view2):

  (map (fn [x i]
                    (om/build (if cond test-view1 test-view2) x 
                        {:key :id
                         :om.core/index i
                         :init-state {:comm comm :test :shouldnt-be-here}}))
                  all-data (range))
swannodette commented 10 years ago

This issue does not have enough information. Please provide a complete minimal example. Thanks.

swannodette commented 10 years ago

This is not a bug, it is a known limitation. Components are identified with their functions. If you want life cycle methods to be called you must use different functions. For example instead the multimethod could return the function to invoke instead of immediately invoking it. I'll probably cover this subtle point in a later tutorial.