인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

날리는달님의 프로필 이미지
날리는달

작성한 질문수

[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!

riverpod 2.0 Notifer 관련하여 질문드립니다

해결된 질문

작성

·

849

·

수정됨

0

riverpod 2.0에서는 StateNotifier대신 Notifier이나 AsyncNotifier를 사용하라고 되어있던데
그러면 현재 강의에서 StateNotifer를 Notifier로 바꿀려고하니 의존성주입을 할때,

StateNotifierProvider에서 생성자로 ref.watch로 authRepository,userMeRepository,storage를 넣어주는데

궁금한것이
1.이를 Notifier에서는 어떻게 넣어주는게 가장 좋은 선택인가요??(생성시에 ref.watch로 한번만 만들기 vs 필요한곳마다 ref.watch사용하기 )

  1. 초기 생성할때 UserModelLoading()을 한뒤에 state업데이트를 getMe함수에서 하는데 이를 try-finally로 하는것이 맞는 방법인가요?

  2. late final AuthRepository, late final UserMeRepository, ... 과 같이 final을 붙일시에
    다시 build되는 상황이 생기던데 에러가 뜨던데 final을 안해도 괜찮은건가요?

아래는 저가 바꿔본 코드입니다.

final userMeProvider = StateNotifierProvider<UserMeStateNotifier,UserModelBase?>((ref) {
  final authRepository = ref.watch(authRepositoryProvider);
  final userMeRepository = ref.watch(userMeRepositoryProvider);
  final storage = ref.watch(secureStorageProvider);
  
  return UserMeStateNotifier(
    authRepository: authRepository,
    repository: userMeRepository,
    storage: storage,
  );
});

class UserMeStateNotifier extends StateNotifier<UserModelBase?> {
  final AuthRepository authRepository;
  final UserMeRepository repository;
  final FlutterSecureStorage storage;

  UserMeStateNotifier({
    required this.authRepository,
    required this.repository,
    required this.storage,
  }) : super(UserModelLoading()) {
    //내 정보 가져오기기
    getMe();
  }

  Future<void> getMe() async {
    final refreshToken = await storage.read(key: REFRESH_TOKEN_KEY);
    final accessToken = await storage.read(key: ACCESS_TOKEN_KEY);

    if (refreshToken == null || accessToken == null) {
      state = null;
      return;
    }

    final resp = await repository.getMe();
    state = resp;
  }

  /*
  *login, logout생략
  */
}

 

final userMeProvider = NotifierProvider<UserMeNotifier,UserModelBase?>(UserMeNotifier.new);

class UserMeNotifier extends Notifier<UserModelBase?>{
  late AuthRepository authRepository;
  late UserMeRepository repository;
  late FlutterSecureStorage storage;
  @override
  UserModelBase? build() {
    try{
      authRepository = ref.watch(authRepositoryProvider);
      repository = ref.watch(userMeRepositoryProvider);
      storage = ref.watch(secureStorageProvider);
      return UserModelLoading();
    }finally{
      getMe();
    }
  }

  Future<void> getMe() async {
    final refreshToken = await storage.read(key: REFRESH_TOKEN_KEY);
    final accessToken = await storage.read(key: ACCESS_TOKEN_KEY);

    if (refreshToken == null || accessToken == null) {
      state = null;
      return;
    }

    final resp = await repository.getMe();
    state = resp;
  }

}

답변 1

1

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

안녕하세요!

특정 패키지의 사용 방법과 문법은 충분히 언제든지 바뀔 수 있습니다.

하지만 기본 기념은 절대로 변하지 않습니다.

디펜던시의 ref.watch를 하는 위치는 절대적으로 Provider를 선언하는 위치입니다.

왜냐면 Notifier의 경우 (어떤 형태의 Notifier든) 의존성이 있는 다른 Provider 들의 변화가 있을때 다시 빌드를 해서 변화에 대처해야하기 때문입니다.

위 글을 잘 이해했다면 이미 1,2,3번의 답변이 모두 자동으로 됩니다.

StateNotifier 클래스가 State로 변경되든 Notifier로 변경되든 근본적인 특성을 그대로 유지하는 이상 StateNotifier가 하는 역할은 똑같습니다.

저희는 Provider 선언에서 의존성을 watch() 해주고 constructor로 의존하는 값을 주입 해주며 (이 방법 외엔 없습니다) 의존성의 새로운 변화가 있을때는 인스턴스를 새로 생성해줘야합니다.

그렇기 때문에 build() 함수 내부에서 watch()를 실행하시는건 당연히 안됩니다.

말씀하신 공식 다큐멘테이션에서도 Provider 선언하는 부분에서 watch()를 하고 있고 Notifier의 build() 함수에서는 watch()를 하지 않습니다.

https://docs-v2.riverpod.dev/docs/providers/provider

감사합니다!

날리는달님의 프로필 이미지
날리는달
질문자

그렇다면 이 경우는 함수 내부마다 ref.watch()로 사용하고
getMe를 사용하려면 AsyncNotifer로 만들면 되는것인가요?

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

watch를 provider 선언에 사용하셔야합니다. getMe()는 UserMeRepository의 함수이기 때문에 어떻게든 주입만되면 사용 하실 수 있습니다.

날리는달님의 프로필 이미지
날리는달
질문자

선생님 여러번 질문하여 죄송합니다...
공식문서, stackoverflow에 찾아봐도 안보여서 질문드립니다..
stateNotifier처럼 constructor에 watch로 넘겨주는 방식을 notifier에는 찾아볼수가 없는데(ref가 없어서) notifierProvider에서 어떻게 선언에서 넘겨주나요? notifierProvider을 Provider로 감싸려고해도 생성자로 넘겨주는 방법을 못찾겠습니다.

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

제가 착각 한 것 같은데 코드를 다시 보니 불가능 한 것 같습니다. prefer은 꼭 전환하라는게 아니라 선호하라는 뜻입니다. 아쉽게도 원하시는 기능은 현재 상태에선 불가능해보이니 강의대로 StateNotifierProvider를 사용하셔아 할 것 같습니다. 아직 관련 이슈들이 많이 열려있는걸로 보아하니 추후 개선될걸로 기대 해봅니다.

날리는달님의 프로필 이미지
날리는달

작성한 질문수

질문하기