Riverpod
一、使用目的
Riverpod是一個flutter使用的狀態管理工具。
二、官網及下載處
pub:https://pub.dev/packages/riverpod
三、使用方法:
(一)在使用時,一般在程式的入口main()中,加入ProviderScope(child: MyApp()),這樣於下運作的程式才能使用全域常數的功能
void main() {runApp(ProviderScope(child: MyApp()));
}
(二)六種不同情況的引入方式及用法
(1)Provider 宣告一個在任何地方都可以使用及讀取的全域常數。
宣告的方法如下:
//宣告number為一個Provider<int>類型的全域變數,切始值為0
(1-1)需要一個全域的int常數時,宣告為Provider<int>
final Provider<int> number=Provider<int>((ProviderRef ref) {
return 0;
});
要在別的位置取得這個值,可以在可使用ref的地方,使用以下的寫法
ref.watch(number)
或將其值賦予一個變數,以便在後面使用:
final getNumber=ref.watch(number);
(1-2)需要一個全域的String常數時,宣告為Provider<String>
final Provider<String> countryProvider = Provider<String>((ProviderRef ref) {
return 'Taiwan';
});
要在別的位置取得這個值,可以在可使用ref的地方,使用以下的寫法
ref.watch(countryProvider)
或將其值賦予一個變數,以便在後面使用:
final getNumber=ref.watch(countryProvider);
(1-3)需要一個全域的方法,宣告為Provider<方法>
(1-3-1) 不傳入參數
final Provider<Location> locationProvider = Provider((ProviderRef ref) {
return Location();
});
(1-3-2)若要傳入一個參數,可再自己新增
final Provider<Location> locationProvider = Provider((ProviderRef ref) {
return Location(providerRef: ref);
});
為了便於透過ProviderRef 類型的ref,引入其它的Provider,因此這裡將它當作location傳入建構式中,寫法如下:
final Provider<Location> locationProvider = Provider((ProviderRef ref) {
return Location(providerRef: ref); //這裡多了一個傳入的參數
});
class Location {
final ProviderRef providerRef;
Location({required this.providerRef}); //與之搭配的建構式
String get info { //下面使用了傳入的providerRef,以便引入其它的全域Provider,做其它使用
final String country = providerRef.read(countryProvider); //taiwan
final String city = providerRef.read(cityProvider); //taipei
return '$country ,$city';
}
}
要在別的位置取得這個Provider,可以在可使用ref的地方,使用以下的寫法
ref.watch(locationProvider)或將其值賦予一個變數,以便在後面使用:
final location=ref.watch(locationProvider);(2)StateProvider 宣告一個可以變得簡單變數
宣告方法如下:
final StateProvider<int> postalCodeProvider = StateProvider((ref) {
return 369;
});
上面的posttalCodeProvider為StateProvider<int>類型,其值為369,與上面的Provider不同的地方,使用者可以透過簡單的方法,改變回傳的369的值。
ElevatedButton(
onPressed: () {
ref.read(postalCodeProvider.notifier).state++;
},
child: const Text('點我加數字'),
),
final postalCode = ref.watch(postalCodeProvider.state).state;
final postalCode = ref.watch(postalCodeProvider);
(3)StateNotifierProvider 宣告多個可以變的變數
StateNotifierProvider和StateProvider用法很相似,StateProvider有一個state可以讀取,寫程式時可以簡單的改變它的值,而StateNotifierProvider它可以建立一個類,其中擴充自StateNotifier,相對於只能操控固定的值,StateNotifierProvider可以進行更靈活的操作。上面程式中< 1,2> ,前面的部份為要傳入類的名字,而後面int則為要傳回值的類型,而最後要回傳(return)的是你要宣告為全域變數的方法,這個方法名要與你建的類建構式相同。final StateNotifierProvider<FamilyNumberProvider, int> familyNumberProvider =
StateNotifierProvider<FamilyNumberProvider, int>((ref) {
return FamilyNumberProvider();
});
class FamilyNumberProvider extends StateNotifier<int> {
//super(0)中的0,預設state變數的值,除了可以是int外,也可以是String,list
//例:super([])
FamilyNumberProvider() : super(0);
//state增加的方法,想寫什麼可以自己設計
void increament() {
state = state + 1;
}
//state減少的方法,想寫什麼可以自己設計
void decreament() {
state--;
}
}
final familyNumber = ref.watch(familyNumberProvider);
(4)FutureProvider flutter中有一些異步的方法,而riverpod有提供了一個可以將異步的方法於全域方法引用的方法,以下為使用的方法示範。
(4-1)任何一個異步的方法,以下會每隔2秒傳回Hello, Riverpod字串
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Hello, Riverpod!';
}
(4-3)顯示於畫面
Widget build(BuildContext context, WidgetRef ref) {
AsyncValue<dataProvider> dataAsyncValue = ref.watch(dataProvider); //利用ref.watch(dataProvider);
return dataAsyncValue.when(
data: (data) => Text(data), //讀取到資料後會在這裡處理,data指的是回傳的資料
loading: () => CircularProgressIndicator(), //讀取中顯示的值
error: (error, stackTrace) => Text('Error: $error'), //讀取錯誤的回傳值
);
})
(5)StreamProvider
這個用法與futureProvider相同,就是其宣告成全域變數的方法為一個Stream,而在宣告時用StreamProvider<回傳類型>((ref){ })取代FutureProvider<回傳類型>((ref) async {})
(6)ChangeNotifierProvider
ChangeNotifierProvider官方並不推薦使用,但在實際使用上,這個方法相對於較於靈活,簡單,如果你的狀態很多,採用這個方法比較容易宣告很多的變數。
宣告成全域變數的方法如下:
final counterProvider = ChangeNotifierProvider<MychangerNotifierProvider>(
(ref) => MychangerNotifierProvider());
其回傳類別的寫法,裡面設了兩個變數_value及_value1
class MychangerNotifierProvider extends ChangeNotifier {要注意擴充的類別為ChangeNotifier,而在其方法裡面,在執行完後,要加上notifyListeners();更新畫面,否則畫面不會更新。
var _value = 0;
var _value1 = 0;
int get value => _value;
int get value1 => _value1;
void increament() {
_value++;
notifyListeners();
}
void decreament() {
_value1--;
notifyListeners();
}
}
final counter = ref.watch(counterProvider);
.family
有時候,在使用ref時,會有丟入參數的需要,而.family就可以在引用時丟入一個參數。
宣告的方法如下:
//.family
final message = Provider.family((ref, int myvalue) {
return Location2(providerRef: ref, number: myvalue);
});
第二個參數,就是在引用時,要丟入的值。
回傳的loction2類的寫法如下:
class Location2 {
final ProviderRef providerRef;
int number;
Location2({required this.providerRef, required this.number});
int get info {
return number;
}
count() {
number++;
}
}
而若要顯示於畫面的寫法如下:
final message=ref.watch(messageProvider(5));
記得要在引入的Provider後加入你要給的參數。
其後可能在畫面中,適當的地方顯示出這個message,如Text(message.info.toString())。
參考網頁:
Flutter Riverpod 輕鬆學,簡單處理狀態管理!
Flutter Riverpod 輕鬆學(二),一些進階用法!
沒有留言:
張貼留言