หลักการออกแบบเบื้องหลัง miniriverpod.
แพ็กเกจนี้จงใจลดทอนฟีเจอร์เพื่อให้พฤติกรรมชัดเจน: เอกลักษณ์ของ provider ด้วย args, การ inject แบบ scoped และ semantics ของการ dispose ที่คาดเดาได้.
สิ่งที่เปลี่ยนไปจาก Riverpod
แทนที่จะใช้ generated family classes และ channels ของ notifier แบบ implicit, miniriverpod เลือก subclass + args + explicit invoke.
เอกลักษณ์ของ provider
runtimeType + hash ของ args
ทางเลือกแทน family
สืบทอด Provider / AsyncProvider และส่ง super.args((...))
DI fallback
Scope<T>.required + overrideWithValue
ทำไมสิ่งนี้จึงสำคัญ
คุณสามารถใช้ constructor ของ Dart ปกติเพื่อให้เหตุผลเกี่ยวกับ equality และ overrides ได้ ซึ่งทำให้การ debug และการทดสอบตรงไปตรงมา.
การระบุ Provider ด้วย args
args กำหนดคีย์ของ provider ดังนั้น args ที่เท่ากันหมายถึง cache entry เดียวกันภายใน ProviderContainer.
กฎเอกลักษณ์
ผลลัพธ์เชิงปฏิบัติ
- ไม่จำเป็นต้องมี family type แยกต่างหาก.
- การ override ราย argument ทำได้โดยการสร้าง provider instances.
- ควรรักษา args ให้คงที่และไม่เปลี่ยนแปลงเพื่อ caching ที่คาดเดาได้.
ตัวอย่าง: provider แบบ family + Scope สำรอง
ใช้ argument ของ constructor เป็นตัวระบุ และ inject instance สำรองผ่าน Scope.
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(),
);
ขั้นตอนถัดไป
Providers และการอ่าน
ดูรูปแบบที่เป็นรูปธรรมสำหรับ watch/read/listen และ AsyncProvider.future.
เปิด Providers