Fork me on GitHub
#re-frame
<
2020-02-21
>
Setzer2210:02:20

Hi! I'm working on a very basic chat app with re-frame, but I'm having trouble understanding how to treat side effects. I have the most basic use case for a chat box: Whenever a new message is sent, the scroll box must scroll to the bottom (to simplify, let's say this is done always). So I implemented an event (the message being sent) and an effect (the box scrolling to the bottom). The event triggers the aforementioned effect:

(rf/reg-fx
 ::scroll-chat-to-bottom
 (fn [value]
   (when value
     (let [msg-history (-> js/document (.getElementById "message-history"))]
       (set! (.-scrollTop msg-history) (.-scrollHeight msg-history))))))

(rf/reg-event-fx
 ::send-chat-message
 (fn-traced [{db :db} [_ msg]]
           {:db (update db :chat-messages conj msg)
            ::scroll-chat-to-bottom true}))
Now, this has a bug: Whenever a message is sent, the chatbox is first scrolled, and then the db is updated, which triggers a view update. Because the scroll is set first, the chatbox will always be at the second to last message. So, I guess I need a way to trigger an effect after the view has updated. Is there a way I can do this? I have the feeling I'm not modelling this the "re-frame" way, so please feel free to correct my overall approach on this.

mikethompson10:02:42

So, I'd state the problem as ... What you have at the moment is a side effect called scroll-right-now But what you need is instead a side effect which is scroll-soon-but-after-the-next-render

mikethompson10:02:52

So the only problem you have is in writing this better side effect ...

mikethompson11:02:19

Probably a bug in this ... but something like ...

(rf/reg-fx
 ::scroll-chat-to-bottom
 (fn [value]
   (when value
     (reagent/after-render
       (fn []
         (let [msg-history (-> js/document (.getElementById "message-history"))]
         (set! (.-scrollTop msg-history) (.-scrollHeight msg-history)))))))

Setzer2211:02:01

many thanks!! 😄 I'll try this right away

Setzer2211:02:57

it works 👍