profile repository, state, provider

hunnypooh·2022년 10월 31일

해당 강의를 학습하면서 정리한 글입니다. (강력추천)
https://www.udemy.com/course/flutter-provider-essential-korean/

profile_repository

  • repository 폴더 안에 profile_repository.dart 생성
    • FirebaseException 에러와 그 외 케이스로 나눠서 작성.
      • Firebase의 에러의 message는 nullable이라서 ! 사용
      • 그 외 에러에서는 CustomError에서 plugin은 임의로 ‘flutter_error/server_error’로 줌
import 'package:cloud_firestore/cloud_firestore.dart';

import '../constants/db_constants.dart';
import '../models/custom_error.dart';
import '../models/user_model.dart';

class ProfileRepository {
  final FirebaseFirestore firebaseFirestore;
  ProfileRepository({
    required this.firebaseFirestore,
  });

  Future<User> getProfile({required String uid}) async {
    try {
      final DocumentSnapshot userDoc = await usersRef.doc(uid).get();

      if (userDoc.exists) {
        //firestore에서 읽어오는 document가 존재하지 않을 수도 있음.
        final User currentUser = User.fromDoc(userDoc);

        return currentUser;
      }

      throw 'User not found';
    } on FirebaseException catch (e) {
      throw CustomError(
        code: e.code,
        message: e.message!,
        plugin: e.plugin,
      );
    } catch (e) {
      throw CustomError(
        code: 'Exception',
        message: e.toString(),
        plugin: 'flutter_error/server_error',
      );
    }
  }
}

profile_state

  • status를 enum으로 선언
    • initial : 초기상태
    • loading : firestore에서 데이터 가져오는 중
    • loaded : firestore에서 데이터 가져온 상태
    • error : 에러
  • state 클래스에 변수 3개 만들고 1)generate constructor 2)equatable 3)tostring 4)copywith
  • ProfileState의 intial 상태로 만들 factory 코드 작성
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:equatable/equatable.dart';

import 'package:fb_auth_provider/models/custom_error.dart';

import '../../models/user_model.dart';

enum ProfileStatus {
  initial,
  loading,
  loaded,
  error,
}

class ProfileState extends Equatable {
  final ProfileStatus profileStatus;
  final User user;
  final CustomError error;
  ProfileState({
    required this.profileStatus,
    required this.user,
    required this.error,
  });

  factory ProfileState.initial() {
    return ProfileState(
      profileStatus: ProfileStatus.initial,
      user: User.initialUser(),
      error: CustomError(),
    );
  }

  
  List<Object> get props => [profileStatus, user, error];

  
  bool get stringify => true;

  ProfileState copyWith({
    ProfileStatus? profileStatus,
    User? user,
    CustomError? error,
  }) {
    return ProfileState(
      profileStatus: profileStatus ?? this.profileStatus,
      user: user ?? this.user,
      error: error ?? this.error,
    );
  }
}

profile_provider

  • 프로필 상태가 변할때마다 리스너에게 알려줘야해서 ChangeNotifier와 믹스인.
  • profile repository의 getProfile 함수 호출할거니까 instance로 받아옴.
  • getProfile 은 특정 유저의 정보를 가져오니까 매개변수로 uid를 받아옴.
  • catch에서 모든 에러를 CustomError로 변형시킨 후 throw 했다는 걸 기억하기!
import 'package:flutter/foundation.dart';

import '../../models/custom_error.dart';
import '../../models/user_model.dart';
import '../../repositories/profile_repository.dart';
import 'profile_state.dart';

class ProfileProvider with ChangeNotifier {
  ProfileState _state = ProfileState.initial();
  ProfileState get state => _state;

  final ProfileRepository profileRepository;
  ProfileProvider({
    required this.profileRepository,
  });

  Future<void> getProfile({required String uid}) async {
    _state = _state.copyWith(profileStatus: ProfileStatus.loading);
    notifyListeners();

    try {
      final User user = await profileRepository.getProfile(uid: uid);

      _state = _state.copyWith(
          profileStatus: ProfileStatus.loaded, user: user); //성공했으니까 새로운걸로 생성
      notifyListeners();
    } on CustomError catch (e) {
      _state = _state.copyWith(profileStatus: ProfileStatus.error, error: e);
      notifyListeners();
    }
  }
}

main에 inject

  • profile repository는 auth repository와 유사하니까 복붙하고 바로 밑에 추가하고 약간 수정.
  • profile provider는 signup provider와 유사하니까 복붙하고 바로 밑에 추가하고 약간 수정.
return MultiProvider(
  providers: [
    Provider<AuthRepository>(
      create: (context) => AuthRepository(
        firebaseFirestore: FirebaseFirestore.instance,
        firebaseAuth: fbAuth.FirebaseAuth.instance,
      ),
    ),
    Provider<ProfileRepository>(
      create: (context) => ProfileRepository(
        firebaseFirestore: FirebaseFirestore.instance,
      ),
    ),
    StreamProvider<fbAuth.User?>(
      create: (context) => context.read<AuthRepository>().user,
      initialData: null,
    ),
    ChangeNotifierProxyProvider<fbAuth.User?, AuthProvider>(
      create: (context) => AuthProvider(
        authRepository: context.read<AuthRepository>(),
      ),
      update: (BuildContext context, fbAuth.User? userStream,
              AuthProvider? authProvider) =>
          authProvider!..update(userStream),
    ),
    ChangeNotifierProvider<SigninProvider>(
      create: (context) => SigninProvider(
        authRepository: context.read<AuthRepository>(),
      ),
    ),
    ChangeNotifierProvider<SignupProvider>(
      create: (context) => SignupProvider(
        authRepository: context.read<AuthRepository>(),
      ),
    ),
    ChangeNotifierProvider<ProfileProvider>(
      create: (context) => ProfileProvider(
        profileRepository: context.read<ProfileRepository>(),
      ),
    ),
  ],
profile
간단한것들 정리

0개의 댓글