reanimatedでreagentのUIを楽しくする

## tl;dr

- reagentは理解できるけど、cssのtransitionとかは厳しい、でもUIには動きを付けたい筆者のような人にオススメの[reanimated](https://github.com/timothypratley/reanimated/)というライブラリがある
- 勉強兼ねて[デモ](https://iku000888.github.io/reanimated-example/)作ってみた。[ソース](https://github.com/iku000888/reanimated-example)

## デモGIF

![demo.gif](https://qiita-image-store.s3.amazonaws.com/0/124830/1019cdc5-dfdf-05e8-d0b7-7c861bd501b7.gif)

##デモのコード

```clj
(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を除外する必要がある。 [参考](https://stackoverflow.com/questions/42941713/clojurescript-duplicate-externs-reagent-addons)

### 追記:

[react-with-addonsへの依存を消すプルリク送った](https://github.com/timothypratley/reanimated/pull/16)のがマージされてリリースされているので最新版では解消されている。


## 主な関数


具体的な使い方は本家の[devcards](http://timothypratley.github.io/reanimated/#!/examples.core)が充実しているのでそちらを見る方が良いが、特に良いと思った物を2つ紹介する

### `reanimated.core/spring`

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

### `reanimated.core/timeline`

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

## 感想

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

## 宣伝

- 12/12日に[clj-nakano](https://clj-nakano.connpass.com/event/71884/?utm_campaign=event_participate_to_owner&utm_source=notifications&utm_medium=email&utm_content=title_link)でSituatedプログラム・チャレンジのClojureを担当しますので是非参加をご検討下さい
- 現在フリーランスClojuristとして仕事をしております。Clojurist月(人月のClojurist版)が足りない等ございましたらお声かけいただければ。

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

では皆様良いお年を〜