📌

asData propertyとは?

2023/10/29に公開

⚙️riverpodの機能らしい?

https://pub.dev/documentation/riverpod/latest/riverpod/AsyncValueX/asData.html

AsyncData<T>?asData
AsyncValueをAsyncDataにアップキャストするか、AsyncValueがAsyncLoading/AsyncErrorの場合はnullを返します。
AsyncDataは、プルツーリフレッシュ中など、まだロード/エラー状態にある可能性があることに注意してください。

go router builderredirectの処理を実装したかったが上手くいかなかった???
FirebaseAuthの認証の情報を取得する必要があったので、riverpodのasDataを使用した。

動作はこんな感じになってます
https://youtu.be/eDMq0LaR770

ソースコードはこんな感じです。riverpodのプロバイダーで囲んでおく必要があります。出ないと、StreamProviderを呼び出せないです。

認証用のプロバイダー

import 'package:firebase_auth/firebase_auth.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

// Firebase Authenticationのインスタンスを生成するプロバイダー
final firebaseAuthProvider = Provider((ref) => FirebaseAuth.instance);

// ログイン状態を監視するプロバイダー
final authStateProvider = StreamProvider((ref) {
  return ref.watch(firebaseAuthProvider).authStateChanges();
});

👤go router builderredirectの処理を組み込んだコード

router.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:value_notifier_example/ui/page/first_page.dart';

import '../../provider/auth_provider.dart';
import '../../ui/page/next_page.dart';

part 'router.g.dart';

// ファイルを自動生成するときは、下のコマンドを実行する.
// flutter pub run build_runner build --delete-conflicting-outputs
final routerProvider = Provider((ref) {
  final authState = ref.watch(authStateProvider);
  return GoRouter(
    debugLogDiagnostics: true,
    routes: $appRoutes,// 自動生成されたファイルからパスを読み込む

    // リダイレクトの処理
    redirect: (BuildContext context, GoRouterState state) {
      // asData?.valueは、riverpodのStreamProviderの値を取得するプロパティ
      final bool loggedIn = authState.asData?.value != null;
      // ログインしていない場合は、ログインページにリダイレクトする
      if (!loggedIn) {
        return const FirstRoute().location;
      }

      // ログインしている場合は、NextPageにリダイレクトする
      return const NextRoute().location;

    },
    // 404ページを指定
    errorPageBuilder: (context, state) {
      return const MaterialPage(
          child: Scaffold(
            body: Center(
              child: Text('Page not found'),
            ),
          ));
    },
  );
});

<FirstRoute>(
  path: '/',
)
class FirstRoute extends GoRouteData {
  const FirstRoute();

  
  Widget build(BuildContext context, GoRouterState state) {
    return const FirstPage();
  }
}

/// [NextPageのルート]
<NextRoute>(
  path: '/next',
)
class NextRoute extends GoRouteData {
  const NextRoute();

  
  Widget build(BuildContext context, GoRouterState state) {
    return const NextPage();
  }
}

⚙️ページを作成

匿名認証を使ってユーザーを登録する画面。登録できたら、リダイレクトの処理が実行され、NextPageへ移動する。

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:value_notifier_example/provider/auth_provider.dart';

class FirstPage extends HookConsumerWidget {
  const FirstPage({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('登録ページ'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(onPressed: () async {
              await ref.read(firebaseAuthProvider).signInAnonymously();
            }, child: const Text('登録')),
          ],
        )
      ),
    );
  }
}

ログイン後のNextPageのログアウトボタンを押すと、認証状態が、falseになるので、FirstPageへリダイレクトする。

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../../provider/auth_provider.dart';

class NextPage extends HookConsumerWidget {
  const NextPage({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ログイン後のページ'),
      ),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(onPressed: () async {
              // ログアウトするメソッド
              await ref.read(firebaseAuthProvider).signOut();
            }, child: const Text('Go Back')),
          ],
        )
      ),
    );
  }
}

main.dartはこんな感じです。

main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:value_notifier_example/firebase_options.dart';

import 'common/router/router.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(const ProviderScope(child: MyApp()));
}

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

  
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp.router(
      routerConfig: ref.watch(routerProvider),
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}

最後に

今回は、asDataとはどんなものなのかを解説した記事というより、認証機能の記事を書いた感じになってしまいました。
値があれば、castして、データを戻り値として返してくれて、エラーか、ロード中だったら、nullを返すと書かれている解説のように思えました。

Discussion