주요 콘텐츠로 건너뛰기

빠른 시작

이 섹션은 Provider 패키지에 익숙한 분들 중 Riverpod에 대해 자세히 알고 싶은 분들을 위해 만들어졌습니다.

무엇보다도 먼저 짧은 시작하기 글을 읽고 작은 sandbox 예제를 통해 Riverpod의 기능을 테스트해 보세요. 그 결과 마음에 든다면 마이그레이션을 확실히 고려해야 합니다.

실제로 Provider에서 Riverpod로 마이그레이션하는 것은 매우 간단합니다.

마이그레이션은 기본적으로 단계적 방식으로 수행할 수 있는 몇 가지 단계로 구성됩니다.

ChangeNotifierProvider로 시작하기

Riverpod로 전환하는 동안 'ChangeNotifier'를 계속 사용하고, 최신의 멋진 기능을 최대한 빨리 사용하지 않는 것도 상관없습니다.

실제로 다음과 같이 시작해도 좋습니다:

// 아래와 같은 코드를 가지고 있다면
class MyNotifier extends ChangeNotifier {
int state = 0;

void increment() {
state++;
notifyListeners();
}
}

// ... 이것만 추가하세요!
final myNotifierProvider = ChangeNotifierProvider<MyNotifier>((ref) {
return MyNotifier();
});

보시다시피 Riverpod은 pkg:Provider에서 마이그레이션을 지원하기 위해 제공되는 ChangeNotifierProvider 클래스를 노출합니다.

이 Provider는 새 코드를 작성할 때 권장되지 않으며, Riverpod을 사용하는 가장 좋은 방법은 아니지만 마이그레이션을 시작하는 부드럽고 매우 쉬운 방법이라는 점에 유의하세요.

'ChangeNotifier'를 더 최신의 Riverpod의 provider들로 '즉시' 변경하려고 서두를 필요는 없습니다. 일부는 약간의 패러다임 전환이 필요하기 때문에 처음에는 어려울 수 있습니다.

먼저 Riverpod에 익숙해지는 것이 중요하므로 천천히 하세요; pkg:provider의 거의 모든 Provider가 pkg:riverpod에 엄격하게 대응한다는 것을 금방 알 수 있습니다.

잎사귀(leaves)부터 시작

다른 것에 의존하지 않는 Provider, 즉 종속성 트리의 잎사귀(leaves)부터 시작하세요.
모든 잎사귀를 마이그레이션한 후에는 잎사귀에 의존하는 Provider로 이동할 수 있습니다.

다시 말해, 처음부터 ProxyProvider를 마이그레이션하지 말고, 모든 종속성을 마이그레이션한 후에 처리하세요.

이렇게 하면 마이그레이션 프로세스가 향상되고 간소화되는 동시에 오류를 최소화/추적할 수 있습니다.

Riverpod과 Provider가 공존할 수 있습니다.

Provider와 Riverpod을 동시에 사용할 수 있다는 것을 기억하세요.

실제로 import alias를 사용하면 두 API를 모두 사용할 수 있습니다. 이는 가독성 면에서도 좋으며 모호한 API 사용을 제거합니다.

이렇게 하려면, 코드베이스에서 각 Provider 가져오기에 대해 가져오기 별칭(alias)을 사용하는 것을 고려해 보세요.

정보

가져오기 별칭을 효과적으로 구현하는 방법에 대한 전체 가이드가 곧 제공될 예정입니다.

Consumer를 바로 사용할 필요는 없습니다

명심해야 할 것은 Riverpod의 Consumer API즉시 사용할 필요는 없다는 점입니다.
마이그레이션을 막 시작한 경우, 위에서 언급한 대로 ChangeNotifierProvider로 시작하는 것이 좋습니다.

위에서 정의한 myNotifierProvider를 고려해 보세요.

내부 코드가 pkg:Provider의 API에 의존하고 있을 가능성이 높으므로, 다음을 사용하여 pkg:Riverpod로 ChangeNotifier를 사용하기 시작하세요.

MultiProvider(
providers: [
ChangeNotifierProvider.value(value: ref.watch(myNotifierProvider.notifier)),
]
)

이렇게 하면 처음에 루트 위젯만 ConsumerWidget으로 변환하면 됩니다.
이렇게 하면 pkg:Riverpod로 마이그레이션하는 것이 훨씬 쉬워집니다.

한번에 하나씩 Provider를 마이그레이션하세요

기존 앱이 있는 경우, 모든 Provider를 한꺼번에 마이그레이션하지 마세요!

장기적으로 모든 애플리케이션을 Riverpod로 이동하려고 노력해야 하지만, 자신을 지치게(burn out) 하지 마세요. 한번에 하나의 Provider씩 처리하세요.

위의 예를 들어보겠습니다. myNotifierProvider를 Riverpod으로 완전히 마이그레이션한다는 것은 다음과 같이 작성하는 것을 의미합니다:

class MyNotifier extends Notifier<int> {

int build() => 0;

void increment() => state++;
}

final myNotifierProvider = NotifierProvider<MyNotifier, int>(MyNotifier.new);

.. 그리고 또한 해당 provider가 소비되는 방식을 변경해야 합니다, 예를 들어 이 provider에 대한 각 context.watchref.watch로 변경해야 합니다.

이 작업은 시간이 다소 걸리고 오류가 발생할 수 있으므로, 한 번에 끝내려고 서두르지 마세요.

ProxyProvider 마이그레이션

pkg:Provider 내에서 ProxyProvider는 다른 Providers의 값을 결합하는 데 사용됩니다; 빌드는 다른 Providers의 값에 따라 반응적(reactively)으로 달라집니다.

Riverpod에서는 대신 providers는 기본적으로 컴포저블이 가능하므로, ProxyProvider를 마이그레이션할 때 한 provider에서 다른 provider로 직접 종속성을 선언하려면 ref.watch를 작성하기만 하면 됩니다.

오히려 Riverpod에서 값을 결합하는 것이 더 간단하고 직관적으로 느껴질 것이므로 마이그레이션을 통해 코드를 크게 간소화할 수 있습니다.

또한 두 개 이상의 providers를 결합할 때, 복잡한 과정을 거칠 필요 없이 ref.watch를 하나 더 추가하기만 하면 바로 사용할 수 있습니다.

빠른(Eager) 초기화

Riverpod의 providers는 최종 전역(global) 변수이기 때문에 기본적으로 지연(Lazy) 초기화 됩니다.

시작 시 일부 워밍업 데이터나 유용한 서비스를 초기화해야 하는 경우, 가장 좋은 방법은 MultiProvider를 넣었던 위치에서 provider를 먼저 읽는 것입니다.

즉, Riverpod은 강제로 초기화할 수 없기 때문에, 시작 단계에서 읽고 캐시하여, 나머지 애플리케이션 내에서 필요할 때 바로 사용할 수 있도록(warm and ready) 할 수 있습니다.

pkg:Riverpod의 Provider들의 초기화에 대한 전체 가이드는 여기에서 확인할 수 있습니다.

코드 생성

Riverpod을 미래에 대비한 방식으로 사용하려면 코드 생성을 권장합니다. 참고로, 메타프로그래밍(metaprogramming)이 보편화되면, 코드 생성 기능이 Riverpod의 기본값이 될 가능성이 높습니다.

안타깝게도 @riverpodChangeNotifierProvider에 대한 코드를 생성할 수 없습니다.
이 문제를 해결하기 위해 다음 유틸리티 확장 메소드(extesion method)를 사용할 수 있습니다:

extension ChangeNotifierWithCodeGenExtension on Ref {
T listenAndDisposeChangeNotifier<T extends ChangeNotifier>(T notifier) {
notifier.addListener(notifyListeners);
onDispose(() => notifier.removeListener(notifyListeners));
onDispose(notifier.dispose);
return notifier;
}
}

그런 다음 다음 코드 생성 구문을 사용하여 ChangeNotifier를 노출할 수 있습니다:

// ignore_for_file: unsupported_provider_value

MyNotifier example(Ref ref) {
return ref.listenAndDisposeChangeNotifier(MyNotifier());
}

"기본" 마이그레이션이 완료되면 ChangeNotifierNotifier로 변경할 수 있으므로 임시 확장이 필요하지 않습니다.
앞의 사례를 예로 들면, "완전히 마이그레이션된" Notifier가 됩니다:


class MyNotifier extends _$MyNotifier {

int build() => 0;

void increment() => state++;
}

이 작업이 완료되고 코드베이스에 더 이상 ChangeNotifierProvider가 없다는 것이 확실해지면 임시 확장자를 완전히 제거할 수 있습니다.

코드 생성은 권장 사항이지만 필수 사항은 아니라는 점을 명심하세요. 마이그레이션에 대해 점진적으로 생각하는 것이 좋습니다: 한 번에 코드 생성 구문으로 전환하면서 마이그레이션을 구현하는 것이 과하다고 생각되면 점진적으로 마이그레이션을 고려하는 것이 좋습니다.

이 가이드에 따라 나중에 한 단계 더 나아가 코드생성으로 마이그레이션할 수 있습니다.