はじめに
少し期間が空いてしまいましたが、ブログを更新します。
今回は理解できていれば簡単なのに、なかなか実装できなかったReactアニメーションについてです。
これが何でかすご〜く苦労したんですね…
筆者自身が詰まったところから紐解く形で解説を載せていきたいと思います。
Counterサンプルにアニメーションを追加しよう!
まずはネタとして前回まで基礎を学ぶのに利用したCounter
サンプルを利用します。
元々のCounter
サンプルとは以下のものになります。
実装されている機能としては下記の4つになります。
- 「+」ボタンを選択するとClick数が+1される
- 「-」ボタンを選択するとClick数が-1される
- 「Increment if odd」ボタンを選択するとClick数が奇数のときのみ+1される
- 「Increment async」ボタンを選択すると1秒後にClick数が+1される
これに次の機能を1つ追加します。
- 「Show Toast」ボタンを選択するとToastが表示される
- 「Show Toast」ボタンを連打すると追加でToastが表示される
「Toast って何だろう…!?」と思う人もいるかもしれませんので、念のため説明します。
簡単に言うと、「ユーザにポップアップのような形で知らせるもの」です。
Androidユーザなら必ず見たことがあるはずです。(Android Developers Toasts)
今回目指す完成図は下記になります。
フォルダ構成
まずは例によってフォルダ構成を見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Toast表示のActionを追加
さて、まずはToastを表示するためのAction
を追加しましょう。
1 2 3 4 5 6 7 8 9 10 |
|
おわかりの通り、showToast
がそのActionに該当します。
Toast表示Action発行後のReducer処理
続いて、Reducer
の処理を書いていきます。
機能要件にあった通り、ボタンを連打することで複数のToastを表示します。
後で詳細を説明しますが、個々のToastを区別する必要があるため、固有値を付与します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
それぞれ説明します。
追加(1):
今回は簡単のため各Toastに与えるために固有値をnum
として定義し、初期値を0とします。
これをボタンタップ時にカウントアップして、そのnum
を付与してToastを作成することで個々を区別することができます。
追加(2):
他のボタンをタップしたときにstate.num
がリセットされてしまわないように、...state
を追加して、変化のない値も丸々返すようにしています。
追加(3):
Toast表示Action
がdispatch
された後に検知して、新たなnum
値を返却するために追加しました。
Toast Componentの作成
今回、最も重要なComponent
であるToast Component
を作成していきましょう。
Reactで簡単にアニメーションを作成可能なreact-addons-css-transition-group
のReactCSSTransitionGroup
を使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
ReactCSSTransitionGroup Component
の各パラメータは次の通りの意味です。
- transitionName: 基本となるアニメーション対象要素の名称
- transitionEnterTimeout: 要素が追加された後のタイムアウト時間
- transitionLeaveTimeout: 要素が消えた後のタイムアウト時間?
CSSでもアニメーションを追加するので、transitionEnterTimeout
やtransitionLeaveTimeout
が不要なんじゃないかと思ったりしたのですが、これらをつけないとエラーが出ます。
ReactCSSTransitionGroup
の子要素としてToast表示したいDOM要素を追加します。
この子要素にkey
パラメータとしてnum
を渡しています。
これによってボタン連打で追加される各DOM要素が固有の要素であることを区別しています。
key
の重要性については、React.jsの地味だけど重要なkeyについてを見ることをオススメします。
key
にnum
を渡したいので、Toast
のpropTypes
にnum: React.PropTypes.number.isRequired
と定義しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
アニメーションを実行するにはcss
ファイルでスタイルをつけることも必要です。
それぞれ説明します。
.toats-group
これは単にToast全体の表示位置を右上に固定したかったため追加したスタイルになります。.toast
これはToastのデザインです。.toast:first-child
Toast要素は必ず1つ残り続けてしまうため、1番目の要素は非表示としています。.example-enter
Toastの表示し始めの透明度を設定しています。.example-enter.example-enter-active
Toast表示アニメーションになります。.example-leave
Toastの消え初めの透明度を設定しています。.example-leave-active
Toastの非表示アニメーションになります。
Counter ComponentのボタンからToast表示までの流れ
Toast Component
の作成が完了したので、これをCounter Component
から呼び出すように実装していきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
1つ1つ説明します。
追加 (1):
num
はReducer
で変更された新しいstate
のnum
を受け付けるためにpropTypes
に追加しました。
onShowToast
はボタンクリック時にToast
表示アクションの実行を受け付けるためにpropTypes
に追加しました。
追加 (2):
ボタンアクションで実行するための追加です。
追加 (3):
Toast Component
の描画メソッドです。
1つ目の要素は非表示にCSSで設定しているので、初めから描画してしまって問題ありません。
追加 (4):
新たにpropTypes
として追加したnum
とonShowToast
を利用するために書いています。
追加 (5):
ボタンクリック処理とToast描画処理を書いています。
Toastので位置はCSSで右上固定にしてあるので、DOM位置がどこになろうと問題ありません。
Store周りの修正
最後にStore
周りの修正です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
ここではmapStateToPropsContainer
とmapDispatchToPropsContainer
を実装しているので、Reducer
で新たに作成されたstate
を受け取ります。
それを適切にCounter Component
に渡す必要があります。
追加 (1):
Toast
表示アクションをdispatch
に流し込む必要があるので、showToast
をaction.js
からimport
しています。
追加 (2):
新たに生成されたstate
の値を利用するためにmapStateToPropsContainer
に追記しています。
追加 (3):
dispatch
にToast
表示アクションを流し込む設定を追記しています。
まとめ
さて如何でしたでしょうか?
上記実装をすることで連打によるToast表示ができるようになったはずです。
ReactCSSTransitionGroup
周りを新たに学ぶ必要があったものの、基本的なRedux
のデータフローを理解していればさほど難しくないことがわかったのではないでしょうか。
筆者は結局のところ、Redux
のデータフロー周りで躓くことが多く、不必要に難しく感じてしまっていました。
アニメーションはWebサイト作りにおいて、なくてはならないものなので、これを機にReact
でのアニメーション作りの基礎を身に着けたいと思います。
と言ったところで本日はここまで。