I have a component that uses a state machine to trigger a remote mutation on button click. The result of this mutation is in another component. How do I pass this back to the originating component? I tried making the downstream component a part of the originating component, and I tried adding a field to the originating component and updating that by swapping on the state atom directly in the state machineβs ok event, neither seem to work. What am I doing wrong, again?
Your last part seems okay though, can you share some code? Also, is ComponentA included all the way up to your root component?
This is the Session component:
(defsc Session
[this {:keys [session/token session/current-user session/error] :as props}]
{:query [:session/token :session/current-user :session/error]
:ident (fn [] [:component/id :session])
:initial-state {}}
(when token
(dom/div (:current-user/email-addr current-user))))
I want to be able to "use" :session/error in another component, Component A. Component A isn't anything special. It is routable. Neither component is included all the way up to the root. I haven't tried that, yet. I can see in the inspector that the data I expect is indeed in the Session component. It's a singleton. I know it's ident. However, I can't figure out how to make use of it within Component ASo if I understand correctly your mutation is directly modifying Session
and you wan't ComponentA
to react on it(?). But I think you should turn it around. Your mutation needs to update the data in ComponentA
's edge to Session
and then ComponentA will get the updated properties and can pass it down to Session.
At least that's how I've always done it.
So your state map might look like
{:component/id ::ComponentA {:session-props {...}}}
But let me try something real quick(It's my first fulcro project, so I'm still learning a lot)
I rather naively tried:
(defsc ComponentA
- [this {:keys [component/id email/addr user/password] :as props}]
- {:query [:component/id :email/addr :user/password form-state/form-config-join]
+ [this {:keys [component/id email/addr user/password sessions/session] :as props}]
+ {:query [:component/id :email/addr :user/password {:sessions/session (get-query Session)} form-state/form-config-join]
@@ -372,6 +372,7 @@
+ (dom/h1 (:session/error session))
Appreciate the help @rob703!
The state machine looks like:
(defstatemachine session-machine
{::uism/actor-names
#{:actor/session-token
:actor/create-session
:actor/delete-session}
::uism/states
{:initial
{::uism/handler
handle-check-session!}
:state/post-check-session
{::uism/events
(merge session-events
{:event/check-session-ok
{::uism/handler
(fn [{:keys [::uism/app ::uism/state-map] :as env}]
(if-let [error (get-in state-map [:component/id :session :session/error])]
(io/pprint {:session/error error}))
(when (get-in state-map [:component/id :session :session/token])
(hist/route-to! routes/default-route))
env)}
:event/check-session-error
{::uism/handler
(fn [env]
(io/pprint {:check-session-error env})
env)}})}
The Session component is the actor for session-token, and ComponentA is the actor for create-session
Ah yes, I'd swap the session state on :component/id ::ComponentA :sessions/session
and then pass it along to to your session component
Sorry, I don't quite understand π
I'm just writing an example, hang in there
The Session component, I'm hoping, can just represent the session state, and not be required to render anything. While, ComponentA, for example, renders a signin form and triggers a remote mutation to create the session
Ah I missed that part, sorry. Yes it doesn't have to render anything. In that case you may want to look at the RAD demos auth system. It isn't fully fleshed out, but it's a start
https://github.com/fulcrologic/fulcro-rad-demo/blob/master/src/shared/com/example/ui.cljc#L55
I think you're trying to do exactly the same
> I think you're trying to do exactly the same Thanks. At least I know I'm not going off in some wildly ridiculous direction π I'll try attaching things to the Root component Thanks!
What's happening here is that the ui-authenticator on line #105 renders the login form for you. That's configured here: https://github.com/fulcrologic/fulcro-rad-demo/blob/master/src/shared/com/example/client.cljs#L43
And as you can see you still need to include your session component somwhere in your UI tree and pass it the props. So the {:authenticator (comp/get-query Authenticator)}
in the RAD demo is the "edge" I was speaking of earlier.
Hope that helps a bit, sorry for having a slow brain today haha π
> Hope that helps a bit, sorry for having a slow brain today haha I really appreciate you taking the time to help me with this! I'm not using RAD, but I'll look though these pointers to see what I can learn
Looking at this now http://book.fulcrologic.com/#_link_queries
Ah true, I forgot about this! I'm using it myself to pull in stuff like global options for dropdowns n stuff
The follow up is quite important: > http://book.fulcrologic.com/#_a_warning_about_ident_and_link_queries This one bit me the first time
(defsc ComponentA
[this {:keys [component/id email/addr user/password sessions/session] :as props}]
{:query [:component/id :email/addr :user/password {[:sessions/session '_] (get-query Session)} form-state/form-config-join]
This is working
Nice, glad you figured it out!
Thanks again for your help, @rob703!
Component "A" has :onClick #(uism/trigger! this :sessions/session :event/create-session! {...})
mutates a Session component. Component A needs to react to changes in the Session component
I've made the Session component a part of Component A's props and query, and invented a duplicate prop in Component A and tried to update that via the state map. Both seemed to do nothing π