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.
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.
