Fork me on GitHub

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:

 (fn [value]
   (when value
     (let [msg-history (-> js/document (.getElementById "message-history"))]
       (set! (.-scrollTop msg-history) (.-scrollHeight msg-history))))))

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


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


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


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

 (fn [value]
   (when value
       (fn []
         (let [msg-history (-> js/document (.getElementById "message-history"))]
         (set! (.-scrollTop msg-history) (.-scrollHeight msg-history)))))))


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


it works 👍