6-2.(p.81)Riverpod_sample


Riverpod_sample

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:photoapp/photo_list_screen.dart';
import 'package:photoapp/providers.dart';
import 'package:photoapp/sign_in_screen.dart';

// 更新可能なデータを渡したいときに使う
final stateProvider = StateProvider((ref) {
  return 0;
});
// Streamをデータとして渡したいときに使う
// ※ autoDisposeを付けると自動的にデータを破棄してくれる
final streamProvider = StreamProvider.autoDispose((ref) {
  return FirebaseFirestore.instance.collection('samples').snapshots();
});
// 状況に応じて渡すデータを切り替えたいときに使う
final scopedProvider = ScopedProvider<int>(null);

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(
    // Providerで定義したデータを渡せるようにする
    ProviderScope(
      child: MaterialApp(
        home: MyWidget(),
      ),
    ),
  );
}

// ConsumerWidgetを継承すると、
// build()からデータを受け取るためのScopedReaderが提供される
class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    // watch()の引数にProviderを指定することで、そのProviderのデータが受け取れる
    // また、データが更新された時は自動的に反映される
    final int state = watch(stateProvider).state;

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            OutlinedButton(
              onPressed: () {
                // ボタンをタップした時など、context.read()で、その時点のデータを受け取れる
                // また、StateProviderは.stateに再代入することでデータを更新できる
                context.read(stateProvider).state += 1;
              },
              child: Text('COUNT: $state'),
            ),
            // Consumerを使うと、
            // コールバックからデータを受け取るためのScopedReaderが提供される
            Consumer(
              builder: (context, ScopedReader watch, child) {
                final asyncStream = watch(streamProvider);

                // StreamProviderからデータを受け取った時は、
                // .when()で状態に応じた処理を行うことができる
                return asyncStream.when(
                  // データの読み込みが完了している場合
                  data: (QuerySnapshot<Map<String, dynamic>> data) {
                    return Column(
                      mainAxisSize: MainAxisSize.min,
                      children: data.docs.map((doc) {
                        return Text(doc.get('value') as String);
                      }).toList(),
                    );
                  },
                  // データが読込中である場合
                  loading: () {
                    return CircularProgressIndicator();
                  },
                  // データの読み込みに失敗した場合
                  error: (e, stackTrace) {
                    return Text(e.toString());
                  },
                );
              },
            ),
            // ProviderScopeを使うとProviderで渡すデータを上書きできる
            ProviderScope(
              overrides: [
                // 2倍したデータを渡す
                scopedProvider.overrideWithValue(state * 2),
              ],
              child: OtherWidget(),
            ),
            ProviderScope(
              overrides: [
                // 10倍したデータを渡す
                scopedProvider.overrideWithValue(state * 10),
              ],
              child: OtherWidget(),
            ),
          ],
        ),
      ),
    );
  }
}

class OtherWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    // 同時に2箇所でOtherWidgetが使われているが、
    // ScopedProviderを使うと渡すデータを切り分けられる
    final scoped = watch(scopedProvider);

    return Text('$scoped');
  }
}