주요 콘텐츠로 건너뛰기

빠른 시작

이 섹션은 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은 ChangeNotifierProvider 클래스를 제공하는데, 바로 pkg:Provider로부터의 마이그레이션을 지원하기 위한 것입니다.

새 코드를 작성할 때는 이 provider를 권장하지 않으며, Riverpod을 사용하는 최선의 방법도 아니라는 점을 기억하세요. 다만 마이그레이션을 시작하기에는 부드럽고 아주 쉬운 방법입니다.

팁

ChangeNotifier를 더 현대적인 Notifier로 당장 바꾸려고 서두를 필요는 없습니다. 일부는 사고방식을 조금 바꿔야 하므로 처음에는 어려울 수 있습니다.

천천히 진행하세요. 먼저 Riverpod에 익숙해지는 것이 중요합니다. pkg:provider의 Provider는 거의 모두 pkg:riverpod에 정확히 대응하는 것이 있다는 사실을 금방 알게 될 것입니다.

리프부터 시작하기​

아무것에도 의존하지 않는 Provider부터, 즉 의존성 트리의 리프(leaf)부터 시작하세요.
모든 리프를 마이그레이션했다면, 그다음 리프에 의존하는 provider로 넘어가면 됩니다.

다시 말해 처음에는 ProxyProvider 마이그레이션을 피하고, 그 의존성이 모두 마이그레이션된 뒤에 다루세요.

이렇게 하면 마이그레이션이 빨라지고 단순해지며, 오류를 줄이고 추적하기도 쉬워집니다.

Riverpod과 Provider는 함께 쓸 수 있습니다​

Provider와 Riverpod을 동시에 사용하는 것도 얼마든지 가능하다는 점을 기억하세요.

실제로 import 별칭(alias)을 사용하면 두 API를 함께 쓸 수 있습니다.
이 방식은 가독성에도 좋고, API를 모호하게 사용하는 일도 없애 줍니다.

이렇게 할 계획이라면 코드베이스의 모든 Provider import에 import 별칭을 사용하는 것을 고려하세요.

정보

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

한 번에 provider 하나씩 마이그레이션하기​

기존 앱이 있다면 모든 provider를 한꺼번에 마이그레이션하려고 하지 마세요!

장기적으로는 애플리케이션 전체를 Riverpod으로 옮기는 것을 목표로 해야 하지만, 무리하지 마세요.
한 번에 provider 하나씩 진행하세요.

위 예제를 보겠습니다. myNotifierProvider를 Riverpod으로 완전히 마이그레이션하려면 다음과 같이 작성해야 합니다:

class MyNotifier extends Notifier<int> {

int build() => 0;

void increment() => state++;
}

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

.. 그리고 그 provider를 사용하는 방식도 함께 바꿔야 합니다. 즉, 이 provider에 대한 모든 context.watch를 ref.watch로 바꿔 써야 합니다.

이 작업은 시간이 걸리고 오류가 생길 수도 있으니, 한꺼번에 서둘러 하지 마세요.

ProxyProvider 마이그레이션하기​

pkg:Provider에서 ProxyProvider는 다른 Provider의 값을 조합하는 데 쓰이며, 그 빌드는 다른 provider의 값에 반응형으로 의존합니다.

반면 Riverpod의 Provider는 기본적으로 조합이 가능합니다. 따라서 ProxyProvider를 마이그레이션할 때 한 Provider에서 다른 Provider로의 직접적인 의존성을 선언하려면 ref.watch만 쓰면 됩니다.

오히려 Riverpod에서 값을 조합하는 쪽이 더 단순하고 직관적으로 느껴질 것이므로, 마이그레이션을 통해 코드가 크게 단순해질 것입니다.

게다가 세 개 이상의 provider를 조합할 때도 복잡한 요령이 필요 없습니다. ref.watch를 하나 더 추가하기만 하면 됩니다.

즉시 초기화​

Notifier는 전역 final 변수이므로 기본적으로 지연(lazy) 초기화됩니다.

앱 시작 시 미리 준비해 둘 데이터나 유용한 서비스를 초기화해야 한다면, 예전에 MultiProvider를 두던 자리에서 provider를 먼저 읽는 것이 가장 좋은 방법입니다.

다시 말해 Riverpod은 즉시 초기화를 강제할 수 없으므로, 시작 단계에서 provider를 읽어 캐시해 두면 애플리케이션의 나머지 부분에서 필요할 때 바로 사용할 수 있습니다.

pkg:Notifier의 즉시 초기화에 대한 전체 가이드는 여기에서 볼 수 있습니다.

코드 생성​

Riverpod을 미래에도 대비된 방식으로 사용하려면 코드 생성을 권장합니다.
참고로, 메타프로그래밍이 도입되면 Riverpod에서는 코드 생성이 기본이 될 가능성이 높습니다.

안타깝게도 @riverpod는 ChangeNotifierProvider에 대한 코드를 생성할 수 없습니다.
이를 해결하려면 다음 유틸리티 확장 메서드를 사용할 수 있습니다:

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());
}

"기본" 마이그레이션이 끝나면 ChangeNotifier를 Notifier로 바꿔 임시 확장이 더 이상 필요 없게 만들 수 있습니다.
앞의 예제를 이어 보면, "완전히 마이그레이션된" Notifier는 다음과 같습니다:


class MyNotifier extends _$MyNotifier {

int build() => 0;

void increment() => state++;
}

이 작업을 마치고 코드베이스에 ChangeNotifierProvider가 더 이상 없다는 것이 확실해지면 임시 확장을 완전히 제거해도 됩니다.

코드 생성은 권장 사항일 뿐 필수는 아니라는 점을 기억하세요.
마이그레이션은 점진적으로 생각하는 것이 좋습니다. 이 마이그레이션과 코드 생성 문법으로의 전환을 동시에 한 번에 진행하는 것이 부담스럽게 느껴진다면, 그래도 괜찮습니다.

이 가이드를 따라 진행한 뒤, 나중에 다음 단계로 코드 생성으로 마이그레이션할 수 있습니다.