Fork me on GitHub
#fulcro
<
2020-11-08
>
tvaughan12:11:09

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?

tvaughan12:11:40

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

tvaughan12:11:38

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 😞

xceno11:11:16

Your last part seems okay though, can you share some code? Also, is ComponentA included all the way up to your root component?

tvaughan11:11:35

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 A

xceno11:11:11

So 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

xceno11:11:44

(It's my first fulcro project, so I'm still learning a lot)

tvaughan11:11:43

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

tvaughan11:11:56

Appreciate the help @U012ADU90SW!

tvaughan11:11:24

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)}})}

tvaughan11:11:51

The Session component is the actor for session-token, and ComponentA is the actor for create-session

xceno11:11:26

Ah yes, I'd swap the session state on :component/id ::ComponentA :sessions/session and then pass it along to to your session component

tvaughan11:11:57

Sorry, I don't quite understand 😞

xceno11:11:17

I'm just writing an example, hang in there

tvaughan11:11:30

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

xceno11:11:37

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

xceno11:11:21

I think you're trying to do exactly the same

tvaughan11:11:53

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

xceno11:11:41

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 🙂

tvaughan11:11:41

> 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

xceno12:11:15

Ah true, I forgot about this! I'm using it myself to pull in stuff like global options for dropdowns n stuff

xceno12:11:59

The follow up is quite important: > http://book.fulcrologic.com/#_a_warning_about_ident_and_link_queries This one bit me the first time

tvaughan13:11:07

(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]

tvaughan13:11:16

This is working

xceno13:11:21

Nice, glad you figured it out!

tvaughan13:11:47

Thanks again for your help, @U012ADU90SW!