flutterでRiverpodとFreezedを使ってカウンターアプリを実装

2025 年 3 月 12 日 by marukor

はじめに

flutterの標準カウンターアプリを、状態管理に Riverpod、データクラスに Freezed を使って実装します。
flutter開発に必須のライブラリなので使い方を習得していきましょう!

完成系はこんな感じです。

環境

os mac

version 3.27.1 

必要なパッケージのインストール

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^2.4.0
  freezed_annotation: ^2.2.0

dev_dependencies:
  build_runner: ^2.4.6
  freezed: ^2.3.5

Freezedを使った状態クラスの作成

import 'package:freezed_annotation/freezed_annotation.dart';

part 'counter_state.freezed.dart';

@freezed
class CounterState with _$CounterState {
  const factory CounterState({@Default(0) int count}) = _CounterState;
}

この CounterState は、count という整数を持つシンプルなデータクラスです。

StateNotifier を使ったカウンターの状態管理

CounterNotifier を作成し、StateNotifierProvider を使って状態を管理します。

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'counter_state.dart';

class CounterNotifier extends StateNotifier<CounterState> {
  CounterNotifier() : super(const CounterState());

  void increment() {
    state = state.copyWith(count: state.count + 1);
  }
}

final counterProvider = StateNotifierProvider<CounterNotifier, CounterState>((ref) {
  return CounterNotifier();
});

UIの作成

カウンターを表示し、ボタンで増やす機能を実装します。

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'counter_notifier.dart';

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Riverpod Freezed Counter',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const CounterPage(),
    );
  }
}

class CounterPage extends ConsumerWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counterState = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);

    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod & Freezed Counter')),
      body: Center(
        child: Text(
          'Count: ${counterState.count}',
          style: const TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: counterNotifier.increment,
        child: const Icon(Icons.add),
      ),
    );
  }
}

コード全文

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'main.freezed.dart';

// Freezedを使った状態クラス
@freezed
class CounterState with _$CounterState {
  const factory CounterState({@Default(0) int count}) = _CounterState;
}

// StateNotifier を使った状態管理
class CounterNotifier extends StateNotifier<CounterState> {
  CounterNotifier() : super(const CounterState());

  void increment() {
    state = state.copyWith(count: state.count + 1);
  }
}

// Providerの定義
final counterProvider = StateNotifierProvider<CounterNotifier, CounterState>((ref) {
  return CounterNotifier();
});

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Riverpod Freezed Counter',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const CounterPage(),
    );
  }
}

class CounterPage extends ConsumerWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counterState = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);

    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod & Freezed Counter')),
      body: Center(
        child: Text('Count: ${counterState.count}', style: const TextStyle(fontSize: 24)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: counterNotifier.increment,
        child: const Icon(Icons.add),
      ),
    );
  }
}

まとめ

  • Freezed を使って状態クラス CounterState を定義。
  • StateNotifier を使って状態管理を行う CounterNotifier を作成。
  • ConsumerWidget を使用して UI で状態を監視。

このように、Riverpod と Freezed を組み合わせることで、状態管理がより安全で扱いやすくなります!

タグ: , ,

TrackBack