Вход в Flutter api с использованием riverpod

Я пытаюсь использовать riverpod для входа в систему с бэкэндом laravel. Прямо сейчас я просто возвращаю из репозитория true или false. Я установил форму, которая принимает электронную почту и пароль. Переменная isLoading предназначена только для отображения индикатора круга. Я запустил код, и он работает, но не уверен, правильно ли я использую Riverpod. Есть ли способ лучше?

auth_provider.dart

class Auth{
  final bool isLogin;
  Auth(this.isLogin);
}
class AuthNotifier extends StateNotifier<Auth>{
  AuthNotifier() : super(Auth(false));
  void isLogin(bool data){
    state = new Auth(data);
  }
}
final authProvider = StateNotifierProvider((ref) => new AuthNotifier());

auth_repository.dart

class AuthRepository{
  static String url = "http://10.0.2.2:8000/api/";
  final Dio _dio = Dio();
  Future<bool> login(data) async {
    try {
        Response response = await _dio.post(url+'sanctum/token',data:json.encode(data));
        return true;
    } catch (error) {
        return false;
    }
  }
}

login_screen.dart

void login() async{
  if(formKey.currentState.validate()){
    setState((){this.isLoading = true;});
    var data = {
      'email':this.email,
      'password':this.password,
      'device_name':'mobile_phone'
    };
    var result = await AuthRepository().login(data);
    if(result){
        context.read(authProvider).isLogin(true);
        setState((){this.isLoading = false;});
    }else
      setState((){this.isLoading = false;});
  }
}

person stalwart1014    schedule 29.01.2021    source источник


Ответы (2)


Поскольку я не использую мобильные устройства и совсем недавно использую flutter + riverpod в своем недавнем проекте, я не могу сказать, что это лучшая практика. Но есть некоторые моменты, которые хотелось бы отметить:

  • Используйте интерфейс такой IAuthRepository для репозитория. Riverpod может действовать как внедрение зависимостей.
final authRepository = Provider<IAuthRepository>((ref) => AuthRepository());
  • Данные сборки для отправки в репозиторий. По возможности следует разделить представление, бизнес-логику и явную реализацию для внешнего ресурса.
  Future<bool> login(String email, String password) async {
    try {
        var data = {
          'email': email,
          'password': password,
          'device_name':'mobile_phone'
        };
        Response response = await _dio.post(url+'sanctum/token',data:json.encode(data));
        return true;
    } catch (error) {
        return false;
    }
  }
  • Не вызывайте репозиторий прямо из презентации / экрана. Вы можете использовать провайдер для своей логики, который вызывает репозиторий
class AuthNotifier extends StateNotifier<Auth>{
  final ProviderReference ref;
  IAuthRepository _authRepository;

  AuthNotifier(this.ref) : super(Auth(false)) {
    _authRepository = ref.watch(authRepository);
  }

  Future<void> login(String email, String password) async {
    final loginResult = await_authRepository.login(email, password);
    state = Auth(loginResult);
  }
}

final authProvider = StateNotifierProvider((ref) => new AuthNotifier(ref));

  • На экране вы можете вызвать login метод провайдера
login() {
  context.read(authProvider).login(this.email, this.password);
}
  • Используйте Consumer или ConsumerWidget, чтобы следить за состоянием и решать, что строить. Также помогает то, что вместо Auth с isLogin для состояния вы можете создать другое состояние. По крайней мере, я обычно создаю абстрактный BaseAuthState, который происходит от AuthInitialState, AuthLoadingState, AuthLoginState, AuthErrorState и т. Д.
class AuthNotifier extends StateNotifier<BaseAuthState>{
  ...
  AuthNotifier(this.ref) : super(AuthInitialState()) { ... }
  ...
}
Consumer(builder: (context, watch, child) {
  final state = watch(authProvider.state);
  if (state is AuthLoginState) ...
  else if (state is AuthLoadingState) ...
  ...
})
person Vayth    schedule 29.01.2021
comment
где именно я бы разместил эти разные состояния? - person stalwart1014; 29.01.2021
comment
они могут быть в том же классе, что и поставщик, если вам не нужно слишком много классов, или они могут иметь свой собственный класс (например, auth_state.dart) для большей ясности. Тебе решать. - person Vayth; 29.01.2021
comment
есть ли причина не вызывать репозиторий прямо из презентации / экрана? - person stalwart1014; 29.01.2021
comment
Для разделения озабоченности. Презентация вызывает домен / бизнес-логику, которая затем использует infra / data / repository. Оба зависят от домена / бизнеса, но не друг от друга. Это поможет в тестировании и управлении зависимостями по мере роста приложения. Это больше говорит об архитектуре программного обеспечения (например, чистая архитектура, ddd и т. Д.), А не о Flutter. Вы можете прочитать о них больше, если вам интересно. - person Vayth; 29.01.2021

Вместо использования bool я предпочитаю использовать перечисления или класс для состояния аутентификации.

enum AuthState { initialize, authenticated, unauthenticated }

и для состояния входа

enum LoginStatus { initialize, loading, success, failed }
person Mr Random    schedule 01.02.2021