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를 사용해도 변하지 않습니다.

다음 단계

프로바이더와 읽기

watch/read/listen과 AsyncProvider.future에 대한 구체적인 패턴을 확인하세요.

프로바이더 열기

뮤테이션

mutation token, mutate, ref.invoke를 사용해 state 업데이트를 구현하세요.

뮤테이션 열기