From mobile-plugin
Flutter Widgetの肥大化を、責務分離・共通化・Riverpod境界の整理でリファクタリングする。build()が長い、Widgetを分割したい、Riverpodのwatch/read/listen/select境界を見直したい、共通化したい、Flutter UIを整理したい時に使用。
How this skill is triggered — by the user, by Claude, or both
Slash command
/mobile-plugin:flutter-widget-splittingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Flutter + Riverpod の Widget 分割と共通化を、実装までつながる形で支援する。
Flutter + Riverpod の Widget 分割と共通化を、実装までつながる形で支援する。
flutter_riverpod / riverpodbuild() / ConsumerWidget / 画面単位のリファクタwatch/read/listen/select 境界に迷う場合は references/riverpod-boundaries.md を読むref.watch は値を使う最小の Widget まで下ろすref.listen、書き込みはイベントハンドラ内の ref.read に寄せるconst 化と builder 系 Widget を優先するbuild() の中身を4種類に色分けするText, Padding, Row, Card, 装飾ref.watch(...) や ViewModel / Notifier の状態Provider / Notifier / AsyncNotifierStatefulWidget / hooks / controllerref.listenref.read(provider.notifier).method()一時 UI 状態を Provider に入れたくなったら、まず route をまたいで共有すべきかを疑う。
TextEditingController やフォーム入力途中の値は原則ローカルに置く。
以下の4層で切る。
Page: Scaffold と画面全体の骨組みSection: 意味のある塊。header, list, action bar などComponent: 再利用できる部品。card, row, tile, button groupLeaf: const にしやすい最小の表示部品watch しないConsumerWidget / Consumer として局所化するselectselectAsyncref.listen は effect 専用 Widget か画面境界に置くconst にできる純 UI を StatelessWidget 化するConsumerWidget 化するStatefulWidget に閉じ込めるbuild() 内の整形や条件分岐が重い場合は Provider / Notifier 側へ移す最初から CommonCard や BaseTile のような抽象度の高い共通Widgetを作らない。
変わる軸が見えた後で API を作る。
Page が provider を読みすぎていないかwatch が最小境界にあるかlisten と read の役割が分かれているかfamily / 引数付き provider が不要に保持されていないかconst と builder 系を落としていないかflutter analyze / flutter test があれば回すclass ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return const Column(
children: [
ProfileHeader(),
ProfileStats(),
],
);
}
}
class ProfileStats extends ConsumerWidget {
const ProfileStats({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final followers = ref.watch(profileProvider.select((it) => it.followers));
final posts = ref.watch(profileProvider.select((it) => it.posts));
return StatsRow(followers: followers, posts: posts);
}
}
listen、更新は readclass SaveProfileButton extends ConsumerWidget {
const SaveProfileButton({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.listen(saveProfileProvider, (_, next) {
next.whenOrNull(
data: (_) => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Saved')),
),
);
});
return FilledButton(
onPressed: () => ref.read(saveProfileProvider.notifier).save(),
child: const Text('Save'),
);
}
}
ConsumerWidget を作り、複数 provider をまとめて watch するread で再ビルドを無理に避けるbuild() や watch と混ぜる_buildHeader() のような method のまま維持する最終的に以下を返す。
watch/read/listen/select の配置npx claudepluginhub caphtech/claude-marketplace --plugin mobile-pluginBuilds cross-platform Flutter apps with state management (Riverpod/Bloc), GoRouter navigation, custom widgets, animations, and performance optimization.
Provides expert Flutter/Dart patterns for cross-platform mobile apps including feature-first project structure, const widget best practices, and Riverpod/Bloc state management.
Builds cross-platform Flutter 3+ apps with Riverpod/Bloc state management, GoRouter navigation, custom widgets, and performance optimization.