パターン・ランゲージエディタの実装方針(rev.0.3)

この記事の読み方(rev.0.2)

読み方っていうほど大したことではないのですが、この記事は開発の中で都度更新予定のものです。
長くなったときに全部読み直すのキチーって思ったので、更新したところは見出しに(rev.x.x)みたいに書いていきます。

はじめに

この記事はドラフトです。(まだ実装したことないから勘で書いてます🥺)
パターン・ランゲージエディタはReact/Reduxを用いて開発します。
この記事では、中~大規模チーム向けと言われているre-ducksパターンを適用した際の実装方針について書いていきます。

参照したもの

Scaling your Redux App with ducks
github alexnm/re-ducks
github jthegedus/re-ducks-examples

大方針(rev.0.2)

Redux-toolkitがあるので、積極的に活用します。
おそらく規模もしれているので、state周りはSliceを使って実装していきます。

プロジェクト構成(rev.0.2)🔧

re-ducksは状態管理(Redux)周りのパターンなのでViewに関しての言及はないみたいですが、この記事ではViewの話も一緒にしていきます。
まず初めに、想定しているプロジェクト構成を示します。(開発中に変更しなさそうなものは除外しています)

pattern-language-editor-client/
├── public/ 
└── src/
    ├── index.css
    ├── index.tsx
    ├── state/
    │   └── feature-name/
    │       ├── index.ts
    │       ├── slice.ts
    │       ├── selectors.ts
    │       └── states.ts
    └── views/
        ├── components/
        ├── containers/
        ├── App.css
        └── App.tsx

次にそれぞれのフォルダ/ファイルの意味と運用方針を示します。タイトルに👀がついているものから読むのをお勧めします。

publicフォルダ

Webpackのモジュールに入れたくない静的リソースを格納する。
「Webpackに入れる==ブラウザでサイトを開いたときに絶対にダウンロードされる」ということなので、妙に大きいデータをWebpackに入れてしまうとサイトの表示に時間がかかるようになってしまいます。
なので、表示が必要になったらその時データをダウンロードします😅みたいなときにpublicフォルダに入れよう。ということだと思うけど今回はおそらくつかわない。

src/index.(tsx|css)(rev.0.2)

このアプリケーションのエントリーポイント。
Providerでstoreを子コンポーネントに引き渡す実装がしてある。
これによって、App以下のコンポーネント間のstoreを経由したデータ変更の通知などができるようになる

src/store.ts(rev.0.2)

state以下に定義したモジュールとviewをつなげるためのデータ群。
state以下にモジュールを追加したときに以下を変更すればOK。

  • import 文を追加

  •  configureStore関数の引数にreducerを追加

👀src/feature-nameフォルダ(rev.0.3)

ここがre-ducksの肝となる部分。機能(feature)毎にfeature-nameフォルダを作成していく。
(フォルダ以下のファイルはテンプレートなだけで必ずしも全部実装する必要はないと思う)
このフォルダに作成するファイルは、redux-toolkitでcreateXXXで作成するインスタンス毎に分けています。(statesは例外)
rev.0.2で実装したpattern featureのフォルダはこんな感じ。

    ├── state/
    │   └── pattern/ # pattern feature
    │       ├── index.ts
    │       ├── slice.ts
    │       ├── selector.ts
    │       └── states.ts

index.ts
patternモジュールが外部に公開するものを列挙。Pythonでいう```__init__.py```的なものとして利用

slice.ts
createSlice() APIで実装するコードを書くところ。
Sliceには、action(イベントが起きたときに実行される関数)とreducer(どのイベントが起きたらどのactionを実行するかジャッジする奴)を実装します。
あと、initialStateも格納するんだけど、これはデータが長くなるかもしれないので、別ファイルstates.tsに分離しました。

states.ts
このfeatureで使用するデータ型と初期状態を定義する。
今は、Patternのデータ型と初期画面表示用のサンプルパターンを書いています。

selector.ts(rev.0.3)
createSelector() APIで実装するコードを書くところ。
Selectorには、機能が持つstateから目的に応じた情報を取得するための処理を実装します。
Selectorによって、viewで機能側のデータ構造を理解する必要なくなるため、機能側の変更影響を受けにくくなります。

src/views/App.(tsx|css)

Viewのエントリーポイント。後述するcontainer、componentsを組み合わせて最終的に表示するWebページの構成を書く。
大きな表示要素の追加がなければ、基本的にcontainer、componentsの変更だけでいいかもしれない。

👀src/views/components(Rev.0.2)

画面を構成するある程度まとまった部品群。
state以下の機能名と被ることがあるので、```xxxComponent.tsx```っていうファイル名にする。
componentsはstateを参照せず、Propsに入力されたデータを表示する処理を記述する。

👀src/views/containers(Rev.0.3)

componentsに表示させるデータを集めたりイベントに何を渡すのかを判断するところ。使いまわしそうにない画面もcontainersに実装する。
(最初は何でもかんでもcomponents/containerのセットにしていたけど似て非なるコードを2個書く感じになったので、基本container、共通的な部品になったらcomponents化のほうがいいと思い始めた)
これによって、componentsを再利用することが可能となる。
パターン・ランゲージエディタではstoreからパターンを取ってくるとか、storeに新しいパターンを追加するときどのreducer/actionを呼ぶか、とかそういうのを書いている。

例)
「ボタン+テキストボックス」がセットになったcomponentsがあったとして、ボタンを押したときにテキストボックスに表示する内容をcontainersを増やすことで切り替える。



この記事が気に入ったらサポートをしてみませんか?