FAC
FAC Flutter Architecture Componentsは、Flutterのクロスコンポーネントリフレッシュと集中状態管理、懸念事項の分離、そして高性能なFlutterページの構築を解決することに特化しています;
Feature
プロバイダーとの比較
- FACは強力なデカップリングデバイスViewModelを提供します;
- 状態を関連付ける、よりクリーンな方法;
- ページまたはアプリの緯度における集中的な状態管理 ViewModelStore;
- より効率的なリフレッシュメカニズム
- initStateでは、データの読み込みやページデータの初期化など、状態の更新をトリガすることができます。
FACコンポーネント・モデルのアーキテクチャ
シンプルな抽象化モデルは、集中管理のためにデータをVMに置き、LiveStateを通してUIをデータに関連付けることができます;
- AACへの類似
これらはすべて、AndroidのネイティブAACコンポーネントに慣れ親しんだ開発者にとっては恩恵です。大きくてかさばるProviderや複雑なReduxフレームワークと比較して、FACを学ぶコストはゼロだからです!
使用シナリオ
- コンポーネントの状態は共有され、コンポーネント間の状態を観察できます。
- クロスコンポーネント通信/
- ターゲットコンポーネントの状態を取得し、それをリフレッシュするための任意のコード位置
- コンポーネントはグローバルな状態を変更する必要があります。
- 大規模で複雑なビジネスや複数ページのネストされたシナリオの構築
FACのインストール
pubspec.yaml の修正
dependencies:
pikach_fac: ^1.0.3
使用方法
エンタープライズ・レベルの複雑なビジネス・シナリオ、コード・レイヤリング、ステート管理への3つのステップ:
- ViewModel と Model データ型の定義
class PageViewModel extends ViewModel {
LiveState<PageModel> pageModel = LiveState<PageModel>(PageModel());
///任意の場所からPageViewModelのインスタンスを取得するための静的メソッドを定義する
static PageViewModel get(BuildContext context) {
return ViewModel.of<PageViewModel>(
context,
builder: () => PageViewModel(),
);
}
///ビジネス実装を定義する
void onCountClick(BuildContext context) {
PageViewModel.get(context).pageModel.setState((value, _) {
_.state.count++;
});
}
}
- LiveState の定義
LiveState<PageModel> pageModel = LiveState<PageModel>(PageModel());
- UI状態へのバインディング
///データとUIバインディングを作成する
PageViewModel.get(context).pageModel.buildWithObserve((ctx, _state) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new Row(
children: <Widget>[
Text(
'カウントが変更されたときだけリフレッシュする、リフレッシュの最適化: ${_state.count}',
),
],
),
);
}, memo: (value) => [value.count])
詳細なコードはGithubご覧ください。
データ・フロー
アーキテクチャ設計の背景
アーキテクチャ設計の本来の意図は、複雑なネストされたページのシナリオでFlutterを解決することであり、効果的にページの状態とリフレッシュ効率を管理することができます!
以下は、FACを使用して開発されたFlutterのページです:
コンポーネント
LiveState
LiveState:観察可能なデータコンポーネント。Liveと呼ぶ原理は、Widgetコンポーネントのライフサイクルを感知することができるからです!
LiveStateは、観測可能なデータ・オブジェクトを構築するため、すなわちモデルを構築するため、データに変更が発生したときにタイムリーにオブザーバに通知するため、およびライフサイクルが合法である場所に通知するため、およびデータ・オブジェクトを配布または転送するために使用することができます;
しかし、モデルオブジェクトをViewModelに変換し、UIとモデルを分離するコード構造を構築することができるように、ViewModelコンポーネントの中に置くことがより推奨されます!
//ViewModelでLiveStateオブジェクトをインスタンス化する
LiveState<ReportRequestModel> _reportRequest;
LiveState<ReportRequestModel> get reportRequest =>
_reportRequest ??= LiveState<ReportRequestModel>(ReportRequestModel());
その他のインターフェイス
LiveStateは、レスポンシブ・プログラミング開発のための他の関連インターフェースを提供します;
- StateOwnerは、ステートへの全体的な変更を提供するために使用されます。
class StateOwner<T> {
T state;
}
- MediatorLiveStateは、複数のLiveStateデータ・ソースをマージするために使用され、レスポンシブ・アプリケーションの構築を容易にします。
- 変換はLiveStateデータソースの変更に使用されますが、dartはリフレクションをサポートしていないため、使用するにはあまり適していないかもしれません!
ViewModel
ViewModel:データとUIを分離、ロジック処理にフォーカス、データとUIの双方向バインディングを構築;
ライフサイクル・セキュリティ
ViewModel の宣言サイクルは現在のページサイクルと同じであるため、メモリリークを心配したり、リサイクルに集中したりする必要はありません;
データとUIの分離
Provider を直接使用するには、手作業で ViewModel を構築し、データと UI を切り離したモデルを構築する必要があり、ViewModel コンポーネントはこの問題を解決するために作成されました!ViewModel は UI が必要とする関連データを管理し、UI とモデル間のインタラクションを引き受け、ビジネスロジックを処理するために使用することができます。ViewModel.of<T>(context)ページ上のどの位置においても、対応する ViewModel インスタンスを , を介して取得することができ、UI とモデル間の双方向の関連付けを確立することができます!ViewModel は、あらゆる種類の複雑なインタラクション、ビジネスロジック、非同期呼び出しなどを処理することができます。すべての変更はモデルに基づいており、モデルは登録された UI オブジェクトと自動的に関連付けられ、単一のデータソースでモデルを構築することができます!
コンポーネント間の通信インターフェースの構築
ViewModel はカスタム コンポーネントのリフレッシュ インターフェイスを提供するために使用されます。例えば、AppBar はタイトルの変更インターフェイスを提供する必要があったり、AppBar の右アクションにショッピング カートの数を表示する必要があったりします。典型的なクロスコンポーネントのリフレッシュ問題は、開発者がオンデマンドで呼び出すことができる ViewModel Aspire インターフェースによって提供することができます!
ViewModelStoreProxyWidget
_ViewModelStore データ ストレージ コンポーネント
Androidのlifecycle-viewmodelコンポーネントパッケージのViewModelStoreコンポーネントと同様に、ViewModelStoreProxyWidgetはページの最上位Widgetとして動作し、InheritedWidgetを通じてページのデータを共有します!Map<Type, dynamic>()final _factoriesByName = Map<String, dynamic>();もちろん、その保存方法はネイティブVMSと同じで、ViewModelを保存するために使用します。さらに、複雑で大規模なアプリケーションシナリオに適応するために、同じ名前で複数のViewModelを保存するための保存方法が追加されました!
設計原則
プロキシの傍受とプロキシの侵入
- プロキシの傍受
どこからでも簡単にデータソースを取得し、UIをリフレッシュできるという利便性の多くは、プロキシ傍受メカニズムによるものです。以下の通りです。ViewModel.of<CountViewModel>(context).model
いわゆるプロキシ機構は、原理は非常に簡単ですが、適切な場所にプロバイダを介してノードの傍受のためのVMSを登録するため、implementWidgetは、傍受の目的を達成するように、データへの一般化されたアクセスを通じて、最も近い位置にされます。ゲイン
外部ページと現在のサブページのデータの混在を防ぎます。
どの位置からでもデータを取得し、UIをリフレッシュすることができます。
プロキシの浸透
プロキシ侵入機構を供給した後、どのように外側のコンポーネントデータを取得しますか?ViewModel はプロキシを貫通させることによって外層データを取得する方法を提供します。
プロキシの傍受とプロキシの浸透のパターンは以下の通りです。
プロキシ侵入デモ
シェア・ストロー
ページは、instanceName パラメータを通じて、1 つの VMS の下で同じ型の複数の ViewModels を共有できます。したがって、1 つのページの下で同じ型の複数のコンポーネントをネストし、異なるコンポーネントのメソッドを呼び出すことができます;
拡張機能
カスタム コンポーネント インターフェイス
カスタム・コンポーネントは、どのようにしてコンポーネントのリフレッシュ・インターフェースを外部に提供するのですか?
プロバイダーの直接使用
Providerのアプローチは、ChangeNotifierによって構築されたModel refresh Providerインスタンスを通して、上位ノードにProviderをマウントすることによって、Consumerの下にあるサブコンポーネントをリフレッシュすることです。このプロセスは、私にとっては異常に長く、過剰に結合されています。
FACの使用
コンポーネントの外部リフレッシュ・インターフェースを提供するカスタム・コンポーネントを提供し、このコンポーネントのリフレッシュ・インターフェースをコードのどこからでも呼び出すことができる方法はありますか?例えば、AppBarはタイトルを変更するためのインターフェイスを提供し、ショッピングカートは商品の数量を変更するためのインターフェイスを提供します;
- LoadingPageの実装
LoadingPageは、ページの読み込み、エラー、空のデータ、表示などの状態を持つページ状態管理コンポーネントです;
FACを使用している場合、ViewModelのインスタンスをページ上の任意の場所で取得することができるため、カスタムWidget LoadingPageを開発する際にVMインターフェースを提供することができます:
PkcPageViewModel.get(context, instance: instance).pageLiveData.setState((value, _) {
value.pageState = PkcPageState.state_loading;
});



