i'm considering adding animations to my card game, but i'm not sure where to begin. currently, the client gets a snapshot of the game state when the game starts, and then gets diffs as players take actions. these diffs are merged into the game state. the game state is rendered with normal reagent hiccup functions, using cursors to keep updates scoped to the specific keys on game state. i'd like to add animations for card movement, as small as a gentle "bump up" when a card leaves the hand and a "drop down" where the card lands on the play area. this is hard to do when i'm just mapping over cards in hand, calling [render-card ...] on each. is there a way to "watch" when a react/reagant node is created or deleted?
You can do it with plain CSS, e.g. https://thinkdobecreate.com/articles/css-animating-newly-added-element/
oh that's cool! is there a way to do the reverse, when it's removed?
To a degree - you can add a particular class, e.g. removing, that triggers the removal animation, and then actually remove the item in the transitionend event handler that you attach to the same element that you're animating.
But that'll probably require also altering the state of your app a bit so it can handle "removed from the business part of the data but not removed from the rendering data" kind of thing.
how do i do that when i'm relying on the ratom to handle those removals?
So a ratom stores a collection of currently visible items?
yeah i have the entire game state in a single ratom and a bunch of cursors to render specific parts (hand, play area, etc). then i just rely on the reactivity to update things when i merge in each diff
Something like this, haven't tested.
(defn item [{:keys [data on-removing-start on-removing-end]}]
(r/with-let [on-transition-end (r/atom nil)]
[:div {:class (when @on-transition-end :removing)
:on-transition-end @on-transition-end}
data
[:button {:type :button
:on-click (fn [_]
(on-removing-start)
(reset! on-transition-end (fn [_] (on-removing-end))))}
"Remove"]]))
(defn the-list []
(r/with-let [items-data (r/atom [...])
;; Use it for business logic.
;; Or make that logic aware of the `:removed?` flag.
not-removed-items (r/reaction (filterv (complement :removed?)
@items-data))]
(into [:div]
(map-indexed (fn [idx data]
[item {:data data
:on-removing-start #(swap! items-data assoc-in [idx :removed?] true)
:on-removing-end #(swap! items-data remove-idx-from-vec idx)}]))
items-data)))hmmm! that's clever
i'll try that out
thank you