JavaScript
Clojure
ClojureScript
reactjs
React
ClojureDay 2

reanimatedでreagentのUIを楽しくする

More than 1 year has passed since last update.

tl;dr

  • reagentは理解できるけど、cssのtransitionとかは厳しい、でもUIには動きを付けたい筆者のような人にオススメのreanimatedというライブラリがある
  • 勉強兼ねてデモ作ってみた。ソース

デモGIF

demo.gif

デモのコード

(ns reanimated.demo
  (:require [reagent.core :as r]
            [reanimated.core :as rc]))

(defn item [s stuff]
  (let [size (r/atom 40)
        spr (rc/spring size)]
    (fn []
      [:div {:on-click #(swap! stuff
                               (fn [stuff]
                                 (assoc stuff s false)))
             :style {:font-size (str @spr "px")
                     :margin "10px"
                     :cursor "pointer"}}
       s
       [rc/timeline
        #(reset! size 100)
        200
        #(reset! size 40)]
       (when-not (get @stuff s)
         [rc/timeline
          #(reset! size 100)
          400
          #(reset! size 20)
          200
          #(swap! stuff dissoc s)
          ])])))


(defn main []
  (let [size (r/atom 40)
        tl (r/atom false)
        spr (rc/spring size
                       {:from 9
                        :velocity .8
                        :mass 2
                        :stiffness 0.13
                        :damping .17})
        stuff (r/atom {"foo" true
                       "bar" true
                       "baz" true})]
    (fn []
      [:div
       [:span {:on-click #(swap! tl not)
               :style {:font-size (str @spr "px")}}
        "click me!"
        (when @tl
          [rc/timeline
           #(reset! size 100)
           200
           #(reset! size 40)
           #(reset! tl false)])]
       [:hr]
       [:div
        [:input {:type "button" :value  "Add stuff"
                 :on-click #(swap! stuff
                                   (fn [stuff]
                                     (assoc stuff (str (gensym "stuff")) true)))}]
        [:input {:type "button" :value  "Remove stuff"
                 :on-click #(swap! stuff
                                   (fn [stuff]
                                     (assoc stuff (ffirst stuff) false)))}]
        [:div {:style {:display "flex"
                       :flex-wrap "wrap"}}
         (->> @stuff
              sort
              (map (fn [[s]] ^{:key s} [item s stuff]))
              doall)]]])))

(r/render [main]
          (js/document.getElementById "app"))

インストールetc

執筆時点での最新→[reanimated "0.5.3"]
注意点として、react-with-addonsに依存しており、
[cljsjs/react-with-addons "15.6.1-0"]
を依存に加える必要があるが、そうすると:advancedモードでビルドする際にreactのduplicate extern的なエラーが出てビルドが出来ない。

reactが重複している事が原因なので[reagent "0.7.0" :exclusions [cljsjs/react]]の様にreagentのreactを除外する必要がある。 参考

追記:

react-with-addonsへの依存を消すプルリク送ったのがマージされてリリースされているので最新版では解消されている。

主な関数

具体的な使い方は本家のdevcardsが充実しているのでそちらを見る方が良いが、特に良いと思った物を2つ紹介する

reanimated.core/spring

  • reagentのatomを引数に取り、reagentのreactionを返す
  • 引数のatomの内部の数値が変更された際に、バネっぽくびよーんとした感じの数値を時系列にreactionに反映する
  • パラメーターでバネの動きを好みに調整することができる

reanimated.core/timeline

  • reagentコンポーネントとして、副作用を定義できる
  • コンポーネントが最初に描画された際の動きをつけることや、ボタンのクリック等に対する動きを書きやすい

感想

  • cssのtransitionとか過去に何回か理解しようとして挫折したので、どうしても自力でアニメーションをつける必要がある時はこのライブラリを使おうと思った
  • コンポーネントに副作用を含める事はアンチパターンとして認識していたが、アニメーションを目的にするのであれば理に叶っているのでは、と思った

宣伝

  • 12/12日にclj-nakanoでSituatedプログラム・チャレンジのClojureを担当しますので是非参加をご検討下さい
  • 現在フリーランスClojuristとして仕事をしております。Clojurist月(人月のClojurist版)が足りない等ございましたらお声かけいただければ。

今年は特に首都圏でClojure大盛り上がりでしたね!
Clojureを使う企業も今後増えていくと思われるので、どんどん普及していくと楽しいなーと思っています。

では皆様良いお年を〜