🐷

SupabaseでProviderを使えない?

2023/12/02に公開

riverpodで呼び出せない?

変数では呼べるがプロバイダーでは呼べない?

内部を見に行って確認するとシングルトンだから、どこからでも呼べるのでそもそもriverpodのプロバイダーを使う必要もないらしい?

import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:supabase/supabase.dart';
import 'package:supabase_flutter/src/constants.dart';
import 'package:supabase_flutter/src/local_storage.dart';
import 'package:supabase_flutter/src/supabase_auth.dart';

/// Supabase instance.
///
/// It must be initialized before used, otherwise an error is thrown.
///
/// ```dart
/// await Supabase.initialize(...)
/// ```
///
/// Use it:
///
/// ```dart
/// final instance = Supabase.instance;
/// ```
///
/// See also:
///
///   * [SupabaseAuth]
class Supabase {
  /// Gets the current supabase instance.
  ///
  /// An [AssertionError] is thrown if supabase isn't initialized yet.
  /// Call [Supabase.initialize] to initialize it.
  static Supabase get instance {
    assert(
      _instance._initialized,
      'You must initialize the supabase instance before calling Supabase.instance',
    );
    return _instance;
  }

  /// Initialize the current supabase instance
  ///
  /// This must be called only once. If called more than once, an
  /// [AssertionError] is thrown
  ///
  /// [url] and [anonKey] can be found on your Supabase dashboard.
  ///
  /// You can access none public schema by passing different [schema].
  ///
  /// Default headers can be overridden by specifying [headers].
  ///
  /// Specify [authCallbackUrlHostname] to let the SDK know what host name auth
  /// callback deeplink will have. If [authCallbackUrlHostname] is not set, we
  /// treat all deep links as auth callbacks.
  ///
  /// Pass [localStorage] to override the default local storage option used to
  /// persist auth.
  ///
  /// Custom http client can be used by passing [httpClient] parameter.
  ///
  /// [storageRetryAttempts] specifies how many retry attempts there should be
  /// to upload a file to Supabase storage when failed due to network
  /// interruption.
  ///
  /// Set [authFlowType] to `AuthFlowType.pkce` to use the PKCE flow for authentication
  /// involving deep links.
  ///
  /// PKCE flow uses shared preferences for storing the code verifier by default.
  /// Pass a custom storage to [pkceAsyncStorage] to override the behavior.
  ///
  /// If [debug] is set to `true`, debug logs will be printed in debug console.
  static Future<Supabase> initialize({
    required String url,
    required String anonKey,
    String? schema,
    Map<String, String>? headers,
    String? authCallbackUrlHostname,
    LocalStorage? localStorage,
    Client? httpClient,
    int storageRetryAttempts = 0,
    RealtimeClientOptions realtimeClientOptions = const RealtimeClientOptions(),
    AuthFlowType authFlowType = AuthFlowType.implicit,
    GotrueAsyncStorage? pkceAsyncStorage,
    bool? debug,
  }) async {
    assert(
      !_instance._initialized,
      'This instance is already initialized',
    );
    _instance._init(
      url,
      anonKey,
      httpClient: httpClient,
      customHeaders: headers,
      schema: schema,
      storageRetryAttempts: storageRetryAttempts,
      realtimeClientOptions: realtimeClientOptions,
      gotrueAsyncStorage:
          pkceAsyncStorage ?? SharedPreferencesGotrueAsyncStorage(),
      authFlowType: authFlowType,
    );
    _instance._debugEnable = debug ?? kDebugMode;
    _instance.log('***** Supabase init completed $_instance');

    await SupabaseAuth.initialize(
      localStorage: localStorage ?? const HiveLocalStorage(),
      authCallbackUrlHostname: authCallbackUrlHostname,
      authFlowType: authFlowType,
    );

    return _instance;
  }

  Supabase._();
  static final Supabase _instance = Supabase._();

  bool _initialized = false;

  /// The supabase client for this instance
  ///
  /// Throws an error if [Supabase.initialize] was not called.
  late SupabaseClient client;
  bool _debugEnable = false;

  /// Dispose the instance to free up resources.
  void dispose() {
    client.dispose();
    SupabaseAuth.instance.dispose();
    _initialized = false;
  }

  void _init(
    String supabaseUrl,
    String supabaseAnonKey, {
    Client? httpClient,
    Map<String, String>? customHeaders,
    String? schema,
    required int storageRetryAttempts,
    required RealtimeClientOptions realtimeClientOptions,
    required GotrueAsyncStorage gotrueAsyncStorage,
    required AuthFlowType authFlowType,
  }) {
    final headers = {
      ...Constants.defaultHeaders,
      if (customHeaders != null) ...customHeaders
    };
    client = SupabaseClient(
      supabaseUrl,
      supabaseAnonKey,
      httpClient: httpClient,
      headers: headers,
      schema: schema,
      storageRetryAttempts: storageRetryAttempts,
      realtimeClientOptions: realtimeClientOptions,
      gotrueAsyncStorage: gotrueAsyncStorage,
      authFlowType: authFlowType,
    );
    _initialized = true;
  }

  void log(String msg, [StackTrace? stackTrace]) {
    if (_debugEnable) {
      debugPrint(msg);
      if (stackTrace != null) {
        debugPrintStack(stackTrace: stackTrace);
      }
    }
  }
}

まとめ

AIに聞いてみるとこんなことがわかった。

riverpodでグローバルに管理しなくて良い?

はい、その通りです。Supabaseクラスはシングルトンパターンを使用しているため、Riverpodを使用してグローバルに管理する必要はありません。Supabase.initializeを呼び出して初期化した後は、Supabase.instanceを通じてどこからでもSupabaseのインスタンスにアクセスできます。

何か他に方法がありそうだが、なんでもプロバイダーで管理する必要がないという意見も最近聞くので、変数を定義して呼び出すことにした。

Discussion