Flex Plugins の Reactサンプルを読み解く
はじめに
みなさん、こんにちは。
KDDIウェブコミュニケーションズの Twilioエバンジェリストの高橋です。
今回は、Flexプラグインを作成するときに事前に理解をしておきたい FlexプラグインでのReactコンポーネント構造について、CLIで作成されるサンプルコードを読み解きながら解説していきます。
FlexプラグインとReactの関係
Flexでは、UIにReactを採用しています。よって、Reactベースでコンポーネントを追加することで、FlexのUIを自由に変更することができます。そのため、Flexでプラグインを開発しようとすると、Reactの知識が不可欠になります。
ここがプラグイン開発のハードルになっていることも事実で、ちょっとでもハードルを下げるために、今回はあまりReactを知らない方でも、なんとなくこんな感じなのねっていうところがわかってもらえればと思って記事を書くことにしました。
とはいえ、80%以上が僕自身の理解を深めるためのものです。
ハンズオン
なにはともあれ、まずは手を動かしながら学習を始めましょう。
Flexプラグイン CLIの準備
以下の記事を参考に、Flexプラグイン CLIをインストールしてください。
Twilio Flex Plugins CLI
そして、記事にも書かれているように、plugin-cli-test
という名前のプラグインを作成しておいてください。
ファイルの構成
出来上がったプラグインは以下のようになっています。
.
├── README.md
├── build
│ ├── plugin-cli-test.js
│ └── plugin-cli-test.js.map
├── jest.config.js
├── node_modules [1102 entries exceeds filelimit, not opening dir]
├── package-lock.json
├── package.json
├── public
│ ├── appConfig.example.js
│ └── appConfig.js
├── src
│ ├── CliTestPlugin.js
│ ├── components
│ │ ├── CustomTaskList
│ │ │ ├── CustomTaskList.Container.js
│ │ │ ├── CustomTaskList.Styles.js
│ │ │ └── CustomTaskList.jsx
│ │ └── __tests__
│ │ └── CustomTaskListComponent.spec.jsx
│ ├── index.js
│ └── states
│ ├── CustomTaskListState.js
│ └── index.js
├── webpack.config.js
└── webpack.dev.js
今回学習する必要があるファイルは、以下の6つです。
- src/CliTestPlugin.js
- src/states/index.js
- src/states/CustomTaskListState.js
- src/components/CustomTaskList.container.js
- src/components/CustomTaskList.Styles.js
- src/components/CustomTaskList.jsx
src/CliTestPlugin.js
具体的には、22行目のinit(flex, manager)
関数が開始時に呼ばれることになりますので、ここから順を追って見ていきます。
23行目にあるregisterReducers(manager)
は、同じファイルの37行目から定義されています。
ここで重要な技術要素が、React-Reduxです。
<参考> React-Reduxって?
Reactもよくわからない人に、React-Reduxを説明するのは難しいのですが、ここでは非常に簡単に説明します。
Reactというのは、コンポーネントという単位でプログラムを作成していくことで、プログラムを部品化し、再利用性を向上させることができます。たとえば以下の図をみるとわかるように、Flex上には色々なコンポーネントがあり、それぞれを部品化することで管理がしやすくなっています。
Reactコンポーネントは通常親子関係をもっており、例えば上の図でいうと、2のMainContainerの中に、3、4、5、16、17のコンポーネントがあります。さらに、16の中には、6と9のコンポーネントがあり、6には更に7と8のコンポーネントが入っています。
Reactでは、各コンポーネントに処理を分割して管理するため、そのコンポーネントで表示するデータなどの状態もコンポーネント単位で管理されます。そのため、親コンポーネントが子コンポーネントを作成するときにデータを渡したり、データの代わりに関数を渡すことで、子コンポーネントから親コンポーネントにデータを渡す仕組みになっています。
このような仕様により、コンポーネントにはそのコンポーネント内の処理だけでなく、他のコンポーネントとのデータのやりとりも実装しなくてはいけません。
この作業を軽減することができるのが、React-Reduxです。
具体的には、コンポーネント内で状態を管理するのではなく、状態を管理する専用のストアと呼ばれる領域を利用し、各コンポーネント間でのやり取りにもこのストアを利用します。ストアに対するデータのやり取りを行う仕組みをReducerと呼び、ストア内のデータはすべてReducer経由で行います。
先程のソースコードの44行目にあるmanager.store.addReducer(namespace, reducers)
で、このプラグインで利用するReducerをFlexプロジェクトのストアに登録しています。
つぎに、ソースコードの25〜30行目を見てみます。
ここでは、flex.AgentDesktopView.Panel1.Content.add(...)
をしていることがわかります。これは先程のコンポーネント全体図をみるとわかるように、16番のAgentDesktopView.Panel1
コンポーネント内に新しいコンテンツを追加することを意味します。
以下の図のように左側の上の方に黒いバーが表示されているのが、今回のプラグインで生成したコンポーネントです。
では次に、add
関数の中に指定されている<CustomTaskListContainer .../>
について見ていきましょう。
この実態は、ソースコードの5行目でインポートされているcomponents/CustomTaskList/CustomTaskList.Container
です。
src/components/CustomTaskList.Container.js
このファイルは、先ほど説明したReact-Reduxの仕組みを使って、実際のプラグインコンポーネントを呼び出す中間ファイルです。
具体的には、15行目で指定しているように、React-Reduxに用意されているconnect
という関数を使って、コンポーネント定義ファイル(同じディレクトリ内にあるCustomTaskList.js
)を呼び出すのですが、その際に、mapStateToProps
とmapDispatchToProps
を引数に渡します。最初の引数であるmapStateToProps
は、コンポーネントに変数を渡すためのものです。具体的には、isOpen
という変数をコンポーネントに渡しています。
とりあえず、変数の内容については後回しにして、実際のコンポーネント定義ファイルを見ていきましょう。
src/components/CustomTaskList.jsx
こちらが今回のプラグインで表示するコンポーネントを定義したものです。
7行目で、パラメータとして受け取ったisOpen
を判定し、false
だった場合はそのまま何もせずに終了します。
isOpen
がtrue
だった場合は、This is a dismissible demo component
という文字列と、close
という文字列を表示しています。後者については、クリックが可能になっており、クリックしたときのイベントに、props.dismissBar
を指定しています。
文字列のスタイルについては、<CustomTaskListComponentStyles>
というファイル(CustomTaskList.Style)で定義しています。
src/components/CustomTaskList.Styles.js
少なくともここまでの情報で、プラグインコンポーネントが表示される仕組みの概要は理解できたかと思います。
ではいよいよ積み残してきたコンポーネントに引き渡す変数や、コンポーネントで実行する関数ハンドラの仕組みについて見ていきましょう。
src/states/index.js
src/states内のファイル(index.jsとCustomTaskListState.js)がReducerを定義したものです。index.js
がインデックスの役割になっています。
一番最初に説明したCliTestPlugin.js
の6行目には以下のような行があります。
import reducers, { namespace } from './states';
これにより、まずsrc/states/index.js
が参照され、namespace
とreducers
がインポートされます。
reducersについては、9〜11行目でreduxのcombineReducersを使ってreducersが返却されています。
export default combineReducers({
customTaskList: CustomTaskListReducer
});
combineReducersは複数のReducerをマージする役目があります(ただし、このコンポーネントではCustomTaskListState
の1つしか定義されていません)。
整理すると、このコンポーネントでは、CustomTaskListStateというReducerが定義されていて、ストアに対する値のやり取りはそこで指定することがわかります。
src/states/CustomTaskListState.js
正直、このファイルの仕組みが一番難解です。
まず、このファイルのreduce
関数(11行目〜)がReducerとなりstateを返します。stateの初期値は、3〜5行目で指定されている通り、isOpen: true
です。
ここで重要な概念が、Actionsです。Reducerを使ってストアの値を操作するには、Actionsというオブジェクトを利用する必要があります。Actionsの構造は以下のようになっています。
{
type: "アクションの種類を一意に識別できる文字列またはシンボル",
payload: "アクションの実行に必要な任意のデータ",
}
これはsrc/states/CustomTaskListState.js
内でいうと、以下の部分になります。
export class Actions {
static dismissBar = () => ({ type: ACTION_DISMISS_BAR });
}
これは、dismissBarという名前のActionsを定義し、このアクションのTypeはACTION_DISMISS_BARであり、payloadは省略されていると読むことができます。
で、実際にこのReducer経由で値を取得するときに実行されるのが、以下の部分です。
export function reduce(state = initialState, action) {
switch (action.type) {
case ACTION_DISMISS_BAR: {
return {
...state,
isOpen: false,
};
}
default:
return state;
}
}
ここでのポイントは、stateの返し方です。具体的には、
return {
...state,
isOpen: false,
}
のように、既存の値を残しながら差分をマージすることです。これによって、他の値を上書き削除しないようにします。
では最後に、コンポーネントの呼び出し時(connect実行時)の動作を解説します。
具体的には、src/components/CustomTaskList.Container.js
の以下の部分です。
const mapStateToProps = (state) => ({
isOpen: state['cli-test'].customTaskList.isOpen,
});
const mapDispatchToProps = (dispatch) => ({
dismissBar: bindActionCreators(Actions.dismissBar, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(CustomTaskList);
先ほど説明したように、このファイルは中間ファイルで、CustomTaskList
コンポーネントを呼び出すときのパラメータを指定しているのが、mapStateToProps
です。
state['cli-test'].customTaskList
でストア内に格納されている現在のstateを参照することができます。コンポーネントを作成するときのisOpen
パラメータは初期値であるtrue
になっています。よって、CustomTaskList
コンポーネントには、{ isOpen: true "}
というパラメータが渡されることになります。
ちなみに、state['cli-test']
のcli-testは、stateのネームスペースです(src/states/index.js
内で指定してあります)。
次に、コンポーネントからストアの値を更新するのが、mapDispatchToProps
です。今回はdismissBar
という名前のハンドラとしてコンポーネントには渡しているので、コンポーネント内では、onClick={props.dismissBar}
という形で利用することができます。
実際の動作としては、reduxに用意されているbindActionCreators
を使ってReducerアクションのバインドを行っています。先程解説したとおり、dismissBarアクションは、TypeとしてACTION_DISMISS_BARを返しますので、結果的にdismissBarを呼び出すと、isOpen
にfalse
が設定され、stateを利用しているコンポーネントの表示が消えることになります。
まとめ
多分一度読んだくらいでは理解できないかと思いますが、実際にコードを色々と弄ってみることで理解が深まると思いますので、ぜひチャレンジしてみてください。
Twilio(トゥイリオ)とは
https://cloudapi.kddi-web.com
Twilio は音声通話、メッセージング(SMS /チャット)、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウド API サービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。
Author And Source
この問題について(Flex Plugins の Reactサンプルを読み解く), 我々は、より多くの情報をここで見つけました https://qiita.com/mobilebiz/items/d666c0f2c974ac37af8e著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .