Why is cursor nil in om/IInitState

165 views
Skip to first unread message

Roger Gilliar

unread,
May 5, 2014, 2:52:22 PM5/5/14
to clojur...@googlegroups.com
I have the following component:

(defn component [services owner]
(reify

om/IInitState
(init-state [_]
{:selected-service nil})

om/IRenderState
(render-state [_ state]
(dom/div nil
(dom/span nil "Service auswählen:")
(dom/div #js {:id "services"}
(apply dom/ul #js {:id "serviceList"} (build-service-list services
(:selected-service state)
owner)))))))

Instead of {:selected-service nil}) in init-state I would like to write

{:selected-service (:name (first services))}

But that does not work since services is nil in init-state. Why ?

David Nolen

unread,
May 5, 2014, 3:00:03 PM5/5/14
to clojur...@googlegroups.com
A complete minimal case would be useful thanks.

David



--
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 clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at http://groups.google.com/group/clojurescript.

Roger Gilliar

unread,
May 5, 2014, 3:42:03 PM5/5/14
to clojur...@googlegroups.com
Just wanted to make sure that this should work. I'll try to build a test case, but I think that the following code is the problem:

om/IRenderState
(render-state [_ state]
(let [services (get-in app-state[:selected-domain :services])
first-name (:name (first services))]
(println first-name)
(if (:show state)
(dom/div nil
(om/build header/component (get-in app-state [:selected-domain]))
(om/build customer-info/component (get-in app-state [:selected-domain :customer-info]))
(om/build service-info/component services
{:init-state {:selected-service first-name}}))
(dom/span nil ""))))))

Maybe it is not a good idea to build components inside the render-state function ?

Message has been deleted

David Nolen

unread,
May 5, 2014, 4:13:20 PM5/5/14
to clojur...@googlegroups.com
There's nothing obvious to me in these examples. A real minimal case is necessary. Thanks.


Roger Gilliar

unread,
May 5, 2014, 4:33:38 PM5/5/14
to clojur...@googlegroups.com
I found the cause of the problem. The components gets rendered twice. On the first call services is nil (therefore it is nil in init state). On the second call it is not nil.

Still don't know why the component gets rendered twice.

Sean Corfield

unread,
May 5, 2014, 7:02:07 PM5/5/14
to clojur...@googlegroups.com
On May 5, 2014, at 1:33 PM, Roger Gilliar <roger....@googlemail.com> wrote:
> I found the cause of the problem. The components gets rendered twice. On the first call services is nil (therefore it is nil in init state). On the second call it is not nil.
>
> Still don't know why the component gets rendered twice.

render and render-state are called a lot more often than you might expect - any time there is a change to the (relevant part of the) global state or to a component's local state (note that the DOM isn't necessarily redrawn for each call to render).

That means you need to think carefully about how and where you are modifying the global / local state - anything that is not "changing" is probably better placed in options (e.g., channels etc).

Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)



signature.asc

Roger Gilliar

unread,
May 6, 2014, 3:56:59 AM5/6/14
to clojur...@googlegroups.com
The problem was that I did one update to the component state and one update to the app-state and both triggered the rendering of the component. Since I did the changes in the wrong order services was null on the first render call.

It would be nice if multiple changes to the state could be combined in a transaction so that the rendering happens after the transaction commits. Is this possible ?

Dave Della Costa

unread,
May 6, 2014, 5:46:31 AM5/6/14
to clojur...@googlegroups.com
You can do this with both cursor data and state.

With the cursor you can use transact!
(https://github.com/swannodette/om/wiki/Documentation#transact) like so:

(transact! data #(assoc % :foo "foo" :bar "bar")) ; etc.

With state you can use update-state!
(https://github.com/swannodette/om/wiki/Documentation#update-state) the
exact same way:

(update-state! owner #(assoc % :foo "foo" :bar "bar"))

DD

Roger Gilliar

unread,
May 6, 2014, 6:12:32 AM5/6/14
to clojur...@googlegroups.com
The question is if I can combine e.g. a transact! and update-state! call into an atomic operation.

Something like:

(do-transact


(transact! data #(assoc % :foo "foo" :bar "bar"))

(update-state! owner #(assoc % :foo "foo" :bar "bar")))

Dave Della Costa

unread,
May 6, 2014, 9:36:10 AM5/6/14
to clojur...@googlegroups.com
I see, sorry I didn't read your previous message more carefully.

From a test (using Om 0.6.2) I just tried it seems like calling
set-state! will trigger two renders in and of itself; calling transact!
multiple times will not do so. I suspect this is either a bug or
something I'm doing incorrectly in my code, but I'll have to ask David
what he thinks:

https://gist.github.com/ddellacosta/432806ff921377510187

However, calling set-state! and transact! together do not provoke extra
re-renders; I haven't dug into the code yet but I suspect any updates
within the same Om/React cycle shouldn't (other than the weirdness with
set-state! I saw) provoke any more than a single re-render.

DD

David Nolen

unread,
May 6, 2014, 9:49:08 AM5/6/14
to clojur...@googlegroups.com
I don't really consider extraneous re-renders a "bug" as I can't think of a situation where it would actually present any problems. How rendering works will always be a bit of an implementation detail - not only because React will likely change this as well sometime in the near future.

David


Dave Della Costa

unread,
May 6, 2014, 10:21:08 AM5/6/14
to clojur...@googlegroups.com
Sorry David, I just posted a new question on the thread regarding this,
so it may be redundant.

I agree that extraneous re-renders should not be a big deal. In fact I
think if re-renders are causing problems in your app-data or state it's
probably because the over-arching logic needs to be re-worked.

That said, I'm mostly just curious what's going on here...seems strange,
but doesn't seem to be anything Om is doing based on reading that code,
maybe behavior in React.
> <mailto:clojurescript%2Bunsu...@googlegroups.com>.
> To post to this group, send email to clojur...@googlegroups.com
> <mailto:clojur...@googlegroups.com>.
> --
> 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 clojurescrip...@googlegroups.com
> <mailto:clojurescrip...@googlegroups.com>.
> To post to this group, send email to clojur...@googlegroups.com
> <mailto:clojur...@googlegroups.com>.
Reply all
Reply to author
Forward
0 new messages