Upgrade to Pro — share decks privately, control downloads, hide ads and more …

新しい風。SolidFlutterで実現するシンプルな状態管理

 新しい風。SolidFlutterで実現するシンプルな状態管理

2025/11/19 に Flutter ZY で発表した登壇資料です。
https://zozotech-inc.connpass.com/event/371380/

株式会社ZOZO
ブランドソリューション開発本部
新規事業部 フロントエンドブロック
大野 純平

#FlutterZY

Avatar for ZOZO Developers

ZOZO Developers PRO

November 19, 2025
Tweet

More Decks by ZOZO Developers

Other Decks in Technology

Transcript

  1. © ZOZO, Inc. 3 https://zozomatch.jp/ 3 • 2025年6月30日提供開始 • 全身見える直感型マッチングアプリ

    • ファッションジャンル診断などの情報をもとに、ZOZO独自のAIが 「好みの雰囲気」の相手を紹介(最大20人/日) • プロフィールに登録された全身写真からユーザー自身の雰囲気も 分析 • 全身写真と自分らしさを表すキャッチコピーを登録するプロ フィールで、個性や魅力が一目で伝わりやすい設計 • 公的証明書を利用した本人確認や24時間365日の監視体制
  2. © ZOZO, Inc. 4 アジェンダ 1. Flutterにおける状態管理の現状 2. “新しい風” SolidFlutterとは

    3. 作者の意図 4. これまでとの相違点 5. 触ってみた 6. 構造 7. 所感 8. まとめ
  3. © ZOZO, Inc. 5 Flutterにおける状態管理の現状 • Stateful Widget • Provider

    (公式推奨パッケージ) • Riverpod (日本では主流) • Flutter Redux • BLoC • etc... 様々な選択肢が存在する ここに新しい風が吹いた!!!
  4. © ZOZO, Inc. 6 “新しい風” SolidFlutterとは SolidFlutter は、Flutter 上に構築された小さなフレームワークで、状態管理ライブラリ •

    SwiftUI と同様に、シンプルで直感的な構文でレスポンシブなコンポーネントを作成できる • SolidFlutterとは、変数にアノテーション (@) を付けるだけで、状態管理や依存性注入が自動で行 われる • solidartでの状態管理のボイラーテンプレートを生成する 他にも関連で • solidart ◦ dart および Flutter アプリケーション用の無料のオープンソース状態管理ライブラリ • solidart_lint といったパッケージが存在する。
  5. © ZOZO, Inc. 7 作者の意図 SwiftUIに影響を受けた(SwiftUI in 2025: Forget MVVM

    の記事) →FlutterでもViewModelをなくすような動きができないか アノテーションで状態管理ができるようになると、状態と UI ロジックを同じ場所にまとめて保存でき、 ViewModelが不要になるのでは !? https://dimillian.medium.com/swiftui-in-2025-forget-mvvm-262ff2bbd2ed より引用
  6. © ZOZO, Inc. 8 これまでとの相違点 Solidartでは、変数にアノテーションを付けるだけで状態管理が可能。 従来のように Provider や Notifier

    を別で実装する必要なし @SolidState() int counter = 0; これだけで依存関係が自動追跡され、UIのうち「counter」を参照している部分だけが再描画される =シンプルな状態管理
  7. © ZOZO, Inc. 9 触ってみた 公式のリファレンスに従って設定 生成コマンドを利用可能に flutter pub add

    solid_annotations flutter_solidart 一応、推奨のlintもインストールした dart pub global activate solid_generator パッケージのインストール
  8. © ZOZO, Inc. 10 触ってみた 生成時に使用するコマンド solid [options] -s, --source

    入力ディレクトリ(デフォルト: source) -o, --output 出力ディレクトリ(デフォルト: lib) -w, --[no-]watch 監視モード(変更を自動反映) -c, --[no-]clean ビルドキャッシュを削除(次回はフルビルド) -v, --[no-]verbose 詳細ログ出力 -h, --[no-]help ヘルプの表示 コマンドオプション一覧 開発時は監視コマンドを実行することが 推奨されていた実装中は裏でずっと起動
  9. © ZOZO, Inc. 11 触ってみた プロジェクトのルート直下に source ディレクトリを作り、その中に main.dart を配置して実装する構成

    Solid は source/ を読み取り、実行に必要なボイラープレートを自動生成して lib/ に出力 my_project/ ├─ pubspec.yaml ├── lib/ │ └─main.dart ← 自動生成 └─ source/ └─ main.dart ← 実装ファイル
  10. © ZOZO, Inc. 12 触ってみた class CounterPage extends StatelessWidget {

    CounterPage({super.key}); @SolidState() int counter = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Computed')), body: Center( child: Text('Counter: $counter'), ), floatingActionButton: FloatingActionButton( onPressed: () => counter++, child: const Icon(Icons.add), ), ); } } カウンターにおける状態管理を実装 (@SolidStateを使用) stateにはアノテーションをつける 使用時は$変数名 →非常にシンプルに状態管理 の実装ができる @SolidStateとは状態変数を 作成できるアノテーション
  11. © ZOZO, Inc. 13 触ってみた class QueryExample extends StatelessWidget {

    QueryExample({super.key}); @SolidState() String? userId; @SolidQuery() Future<String?> fetchData() async { if (userId == null) return null; await Future<void>.delayed(const Duration(seconds: 1)); return 'Fetched Data for $userId'; } カウンターにおける状態管理を実装 (@SolidQueryを使用) 非同期の処理の上に アノテーションをつける 関数内でも$変数が使用可能 @SolidQueryとは非同期の 状態変数を作成できるアノテーション
  12. © ZOZO, Inc. 14 触ってみた Column( children: [ const Text('Complex

    SolidQuery example'), fetchData().when( ready: (data) { if (data == null) { return const Text('No user ID'); } return Text(data); }, loading: , error: , ), ], ), カウンターにおける状態管理を実装 (@SolidQueryを使用) アノテーションをつけた関数を使用 非同期処理の状態に基づいて条 件を出し分け • @SolidQuery(debounce: Duration(seconds: 1))最後の 変更後、実行する前に 1 秒間 待機も可能
  13. © ZOZO, Inc. 15 触ってみた 主機能一覧 • State ◦ Solid

    ウィジェットにリアクティブ状態変数を作成できるもの • Effect ◦ 状態変数が変更するたびに副作用をトリガーするもの • Environment ◦ ウィジェットツリーからSolidウィジェットにプロバイダを注入するもの • Query ◦ ネットワークからデータを取得するなど、非同期データ ソースに基づいてリアクティブ状態 を作成できるもの など、機能は十分揃っている。
  14. © ZOZO, Inc. 16 構造理解 sourceから生成されたボイラーテンプレートがどのようになっているのかコードリーディングする 今回実装例で上げたカウンターにおける状態管理を元に解説する class CounterPage extends

    StatelessWidget { CounterPage({super.key}); @SolidState() int counter = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Computed')), body: Center( child: Text('Counter: $counter'), ), floatingActionButton: FloatingActionButton( onPressed: () => counter++, child: const Icon(Icons.add), ), ); } }
  15. © ZOZO, Inc. 17 構造理解 class CounterPage extends StatefulWidget {

    const CounterPage({super.key}); @override State<CounterPage> createState() => _CounterPageState(); } class _CounterPageState extends State<CounterPage> { final counter = Signal<int>(0, name: 'counter'); @override void dispose() { counter.dispose(); super.dispose(); } lib/main.dartの生成ファイル @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Computed')), body: Center( child: SignalBuilder( builder: (context, child) { return Text('Counter: ${counter.value}'); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => counter.value++, child: const Icon(Icons.add), ), ); } }
  16. © ZOZO, Inc. 18 構造理解 Stateful Widgetに変換される Stateful Widgetでの状態管理とは 違い、定義するときにSignalを使用

    する class CounterPage extends StatefulWidget { const CounterPage({super.key}); @override State<CounterPage> createState() => _CounterPageState(); } class _CounterPageState extends State<CounterPage> { final counter = Signal<int>(0, name: 'counter'); @override void dispose() { counter.dispose(); super.dispose(); } 後半のコードへ続く (変換前はStateless Widget)
  17. © ZOZO, Inc. 19 構造理解 Signalとは、 Signals are the cornerstone

    of reactivity in solidart. They contain values that change over time; when you change a signal’s value, it automatically updates anything that uses it. Signalは、solidartの機能で、値が変わると使っている場所が自動で更新される、賢い変数 →状態管理の根幹 ex) Provider, useState
  18. © ZOZO, Inc. 20 構造理解 パラメーター (new) Signal<int> Signal( int

    value, { bool? equals, String? name, bool? autoDispose, bool Function(int?, int?) comparator = identical, bool? trackInDevTools, bool? trackPreviousValue, }) auto disposeも可能 devtoolsに表示するかとも操作できるのか
  19. © ZOZO, Inc. 21 構造理解 SignalBuilderで変更対象Widgetが囲われている child: SignalBuilder( builder: (context,

    child) { return Text('Counter: ${counter.value}'); }, SignalBuilderとは A signals widget builder. Reacts to any number of signals calling the builder each time. SignalBuilderは、solidartの機能で、Signalのためのウィジェットビルダー 任意の数のSignalに反応し、変更があるたびにbuilderを呼び出す
  20. © ZOZO, Inc. 22 所感 • アノテーションは非常に便利だが、コード生成が、現時点では安定性に課題がある印象(Claude Codeで作ったみたい) → まだ実験段階のフレームワークという位置づけ

    • セットアップがシンプルで、「とりあえず動く」体験がすぐ得られる • lib/ 配下に大量の自動生成コードが作られるため、プロジェクトが大きくなると、パフォーマンス 低下やコードレビューの負担につながりそう • アノテーションの恩恵は大きいが、生成物をどう扱うかは課題になりそう
  21. © ZOZO, Inc. 24 参考文献 • https://solidart.mariuti.com/ • https://solid.mariuti.com/ •

    Flutter in 2025: Forget MVVM, Embrace Fine-Grained Reactivity with SolidFlutter | Blog • https://dimillian.medium.com/swiftui-in-2025-forget-mvvm-262ff2bbd2ed