miniriverpod 뒤의 설계 원칙.
이 패키지는 동작을 명시적으로 유지하기 위해 기능을 의도적으로 줄였습니다: args에 따른 프로바이더 식별, Scope를 통한 스코프 주입, 예측 가능한 해제 의미.
Riverpod에서 무엇이 달라지는가
생성된 family 클래스와 암묵적 notifier 채널 대신, miniriverpod는 subclass + args + 명시적 invoke를 선호합니다.
프로바이더 식별
runtimeType + args hash
family 대안
Provider / AsyncProvider를 subclass로 만들고 super.args((...))를 전달하세요.
DI fallback
Scope<T>.required + overrideWithValue
이것이 중요한 이유
일반 Dart 생성자만으로 equality와 override를 추론할 수 있어 디버깅과 테스트가 단순해집니다.
args를 사용한 프로바이더 식별
args가 프로바이더 키를 정의하므로, args가 같으면 ProviderContainer 안의 캐시 항목도 같습니다.
식별 규칙
실무적 결과
- 전용 family 타입은 필요하지 않습니다.
- 인수별 override는 프로바이더 인스턴스를 생성해 처리합니다.
- 예측 가능한 캐싱을 위해 args는 안정적이고 immutable하게 유지하세요.
예시: family와 유사한 프로바이더 + Scope fallback
생성자 인수를 식별자로 사용하고 Scope를 통해 fallback 인스턴스를 주입하세요.
class ProductProvider extends AsyncProvider<List<Product>> {
ProductProvider({this.search = ''}) : super.args((search,));
final String search;
static final fallback = Scope<ProductProvider>.required('product.fallback');
@override
FutureOr<List<Product>> build(ref) async {
final api = ref.watch(productsApiProvider);
return api.search(q: search);
}
}
// 주입
ProviderScope(
overrides: [
ProductProvider.fallback.overrideWithValue(ProductProvider(search: 'jeans')),
],
child: const App(),
);
Scope는 의존성 연결을 명시적으로 유지해 테스트하기 쉽습니다.
overrideWithValue는 args 기반 인스턴스를 포함해 프로바이더 인스턴스마다 동작합니다.
autoDispose 동작은 subclass + args를 사용해도 변하지 않습니다.