That's what I had in mind. If your current implementation is similar to what's suggested in many react examples, it may not be as bad as I thought. It still feels a little nasty to me though.
Daniel's point about your om version is good too. I had forgotten about the past issues with multimethods. > On 4 Dec 2014, at 21:04, Colin Yates <[email protected]> wrote: > >> On Thursday, 4 December 2014 12:53:27 UTC, Lucas Bradstreet wrote: >> If I understand this correctly, you're actually passing in a om/build'ed >> component as a part of a cursor to another component? I'm not sure whether >> this is the cause but I think this is very likely bad form. > Yes, that is starting to become my intuition as well. > > What would be the analog though of the multitude of React examples where they > compose their components? AIUI those components will be passed through as > props.children, hence I started out this way here. > > A workaround as you say is you pass just the dependant's required cursor and > the dependant builder's var via opts, something like: > > [code] > (defn build-child [cursor owner]...) > (defn wrap-it-up [...] > (om/build some-common-wrapper childs-cursor {:opts {:child-builder > build-child}}) > [/code] > > Is that what you meant? > > (I won't comment on the stylistic qualities of my code, it was under a > comment further up as ";; TODO - prototype" which if I recall correctly is a > license to hack away and then revist "when there is time" :)!) > >> >> If you want to do something like that I would suggest you passed in the >> cursor for the subcomponent that you wish to build, and a fn to build the >> component as an opt. Note, you shouldn't pass in anything via opts that >> should cause a rerender when changed, so this would preclude creating a >> closure over data (your cursor) and passing it via the opts. I would >> probably move all of the cursor building out of :fn and make it happen in >> the multimethod, passing the result to filter-header, along with bound-tree >> fn as an opt. >> >> Then filter-header will call build on bound-tree with the data you passed >> in. >> >> That's all assuming you can't refactor it to avoid this. I've generally only >> used this pattern if I want to wrap components with a generic component >> (e.g. a drag drop component). >> >> Lucas >> >> >> >>> On 4 Dec 2014, at 20:29, Colin Yates <[email protected]> wrote: >>> >>> I have isolated the code in question and it was written very early on (e.g. >>> woooh, here be dragons :)): >>> >>> Essentially I have a component which calls a multimethod to render a child. >>> This is the implementation of that multimethod. This itself uses a common >>> component and passes in components to that common component. >>> >>> Adding a key to the returned component (that isn't a keyword but a >>> string(!)) gives React enough help so it doesn't unmount it. >>> >>> For clarity, filter-header simply displays a nice formatted title and puts >>> "main-component" into the body. >>> >>> [code] >>> (defmethod layout/render-right-component ::consultant >>> [{:keys [owner data]}] >>> (om/build >>> c/filter-header >>> {:id :consultants >>> :main-component >>> (om/build >>> tree/bound-tree >>> nil >>> {:fn (fn [_] {:nodes (om/observe owner (state/all-consultants)) >>> :selected-ids (-> data :filter :consultants >>> :selected-ids) >>> :expanded-ids (-> data :filter :consultants >>> :expanded-ids) >>> :local-search (-> data :filter :consultants >>> :local-search)}) >>> :opts {:change-fn >>> #(search data true) >>> }}) >>> } >>> ;; WITH THIS REACT NO LONGER UNMOUNTS >>> {:react-key "Consultants"}) >>> ) >>> [/code] >>> >>> As to the reduced problem, I need to keep poking, and I still don't >>> understand why it needs the "Consultants" key... >>> >>> This realising components in state (e.g. the :main-component) isn't doing >>> it for me so I think I might utilise more multi-methods. The problem is >>> always how to deliver the focused cursor into the defmethod (e.g. >>> render-right-component really wants to take in the cursor at (:filter >>> :consultants). But that is another experiment. >>> >>> Any advice is welcome. >>> >>> On Thursday, 4 December 2014 12:13:16 UTC, Lucas Bradstreet wrote: >>>>> On 4 Dec 2014, at 20:02, Colin Yates <[email protected]> wrote: >>>>> >>>>> Hi Lucas, thanks for the info. >>>>> >>>>> You are right - I should have been clearer. My scenario is that the >>>>> component hierarchy itself isn't changing only the app-state that the >>>>> hierarchy is mapped to. >>>>> >>>>> In its simplest form, think of a combo-box. The app-state is {:text "" >>>>> :results []}. The component has an input field mapped to :text and a <ol> >>>>> mapped to :results. Changing :text populates :results accordingly. >>>>> >>>>> Your point about keys is worth investigating. Where I am setting keys >>>>> (mainly on dynamic children) they aren't changing. I'm not setting them >>>>> elsewhere though, which might be worth a look. >>>> >>>> Hmm. Maybe the lack of keys on some components may be the issue. Perhaps >>>> react can't assume that the components are the same and thus unmounts and >>>> remounts them (the dom diffing ensures this is still fast) e.g imagine an >>>> unordered list where a list item is inserted mid list. I haven't tested >>>> whether this is true. >>>> >>>>> >>>>> Another clarity question - if an ancestor component is remounted does >>>>> that cause all children to be remounted? It might be something much >>>>> higher up in the hierarchy causing a remount... >>>> >>>> I would think so. Again, I haven't tested this. >>>> >>>>> Thanks for confirming my assumptions anyway, I will dig in a bit deeper. >>>> >>>> Please let us know the result. >>>> >>>> Cheers >>>>> >>>>>> On Thursday, 4 December 2014 11:39:44 UTC, Lucas Bradstreet wrote: >>>>>> Hi, >>>>>> >>>>>> Changes to app state *can* cause components to be unmounted. Imagine a >>>>>> component that renders another component, if a boolean value in the app >>>>>> state is true, otherwise it renders and empty div. When the boolean >>>>>> changes from true to false and the component is re-rendered, the >>>>>> subcomponent will be unmounted. >>>>>> >>>>>> However, if the subcomponent should be re-rendered in both cases, it >>>>>> should not be unmounted. >>>>>> >>>>>> Thinking about it, you're probably mistakenly using a different >>>>>> react-key between the renders. This will cause a new component to be >>>>>> mounted as it is not treated as a continuation of the previous >>>>>> component. >>>>>> >>>>>> Lucas >>>>>> >>>>>> >>>>>>> On 4 Dec 2014, at 19:29, Colin Yates <[email protected]> wrote: >>>>>>> >>>>>>> Hi all, >>>>>>> >>>>>>> I am seeing a component consistently unmount/remount every time the >>>>>>> application state changes. If I change the local state instead then it >>>>>>> doesn't umount but simply re-renders as I expected. >>>>>>> >>>>>>> I didn't expect changes in app-state to cause an unmount/remount only a >>>>>>> re-render (as that is my understanding of React's lifecycle). Further, >>>>>>> since I am talking about this my assumption (and the behaviour I am >>>>>>> seeing) is that om will only call the render protocol method if the >>>>>>> values have actually changed. >>>>>>> >>>>>>> If my assumptions are correct I will see if I can reduce the problem >>>>>>> into a simple gist. >>>>>>> >>>>>>> The reason this is a pain, performance aside, is because a re-mount >>>>>>> loses focus and this specific component is a text field. I notice in >>>>>>> the discussion on text-fields in the Basic tutorial "text" is component >>>>>>> local, maybe now I understand why as this seemed to me to go against >>>>>>> the grain of what is advised to go into local state... >>>>>>> >>>>>>> Can somebody please clarify? >>>>>>> >>>>>>> Thanks! >>>>>>> >>>>>>> -- >>>>>>> Note that posts from new members are moderated - please be patient with >>>>>>> your first post. >>>>>>> --- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "ClojureScript" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>>> an email to [email protected]. >>>>>>> To post to this group, send email to [email protected]. >>>>>>> Visit this group at http://groups.google.com/group/clojurescript. >>>>> >>>>> -- >>>>> Note that posts from new members are moderated - please be patient with >>>>> your first post. >>>>> --- >>>>> You received this message because you are subscribed to the Google Groups >>>>> "ClojureScript" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send an >>>>> email to [email protected]. >>>>> To post to this group, send email to [email protected]. >>>>> Visit this group at http://groups.google.com/group/clojurescript. >>> >>> -- >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "ClojureScript" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to [email protected]. >>> To post to this group, send email to [email protected]. >>> Visit this group at http://groups.google.com/group/clojurescript. > > -- > Note that posts from new members are moderated - please be patient with your > first post. > --- > You received this message because you are subscribed to the Google Groups > "ClojureScript" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/clojurescript. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/clojurescript.
