フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

FlutterでRiverpodを使用してみた

Riverpodとは

状態管理ライブラリです。

Providerの種類

種類 説明
Provider 定数
StateProvider 変数・標準
ScopedProvider 出力を指定する
StateNotifierProvider メソッド付き
FutureProvider Future版
StreamProvider Stream版
ChangeNotifierProvider ChangeNotifierを使う

Consumerの種類

種類 説明
Consumer Widgetに埋め込む
ConsumerWidget StatelessWidgetのRiverpod版
ConsumerStatefulWidget StatefulWidgetのRiverpod版
簡単に実装できるが、パフォーマンスはあまりよくない

表示方法

表示方法 説明
watch 状態変更でWidgetを更新
read 状態変更でWidgetを更新しない
select データ内の特定の値が変更したときのみWidgetを更新する

ConsumerWidget

  • ステータスが更新されるたびに画面全体がリロードされてしまう。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'provider.dart';

void main() {
  runApp(
    // Adding ProviderScope enables Riverpod for the entire project
    const ProviderScope(child: MyApp()),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  MyHomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    print("MyHomePage rebuild");
    return Scaffold(
      appBar: AppBar(
        title: Text(ref.watch(titleProvider)),
      ),
      body: Center(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              ref.watch(messageProvider)
            ),
            Text(
              // ref.watch(countProvider.state).state.toString()
              // ref.watch(countProvider).toString()
              // ref.watch(countProvider.notifier).state.toString()
              ref.watch(countProvider.state).state.toString(),
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.watch(countProvider.state).state ++,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
import 'package:flutter_riverpod/flutter_riverpod.dart';

final titleProvider = Provider<String>((ref) {
  return 'Riverpod Demo Home Page';
});

final messageProvider = Provider<String>((ref) => 'テストテストテストメッセージが入ります');

final countProvider = StateProvider<int>((ref) => 1);

Consumer

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

void main() {
  runApp(
    // Adding ProviderScope enables Riverpod for the entire project
    const ProviderScope(child: MyApp()),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    print("MyHomePage rebuild");
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Consumer(
          builder: (BuildContext context, WidgetRef ref, Widget? child) => Text(
            ref.watch(titleProvider)
          ),
        ),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Consumer(
              builder: (context, ref, child) => Text(
                  ref.watch(messageProvider)
              ),
            ),
            Consumer(
              builder: (BuildContext context, WidgetRef ref, Widget? child) {
                return Text(
                  // ref.watch(countProvider.state).state.toString()
                  // ref.watch(countProvider).toString()
                  // ref.watch(countProvider.notifier).state.toString()
                  ref.watch(countProvider.state).state.toString(),
                  style: Theme.of(context).textTheme.headline4,
                );
              }),
          ],
        ),
      ),
      floatingActionButton: Consumer(
        builder: (context, ref, child) {
          print('button rebuild');
          return FloatingActionButton(
            onPressed: () => ref.read(countProvider.state).state ++,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          );
        },
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}