[英]how to use riverpod, by combing futureprovider with stateprovider?
我正在使用 futureprovider 從 api 獲取響應,但我想從 api 獲取列表並使用 listprovider.state="data from api" 將其分配給 stateprovider,它將如何工作,如何將未來的 provdier 與 state 結合起來提供商。
這是我最近一直在努力思考的話題。
我認為Remi
的回答中缺少的是將Future
數據轉換為可操作數據的能力。
當您使用FutureProvider
接收Future
數據並使用when
方法或使用FutureBuilder
小部件實現 ui 時,它們都會在接收到遠程數據時觸發重建,因此如果您嘗試將值分配給StateProvider
將在另一個將拋出的重建期間觸發重建。
我目前有 2 個解決方法,當我獲得更多相關信息時,我將更新我的答案。
對於這個例子,我們將有一個未來的提供者會等待然后返回一個假數據:
final _futureCounterProv = FutureProvider(
(ref) async {
Future.delayed(
Duration(seconds: 3),
);
return Random().nextInt(100);
},
);
Future.microtask
: Future.microtask
使您能夠在當前重建結束后運行操作。
您必須確保您的StateProvider
依賴項位於Future.microtask
調用下方的Consumer
中,否則Future.microtask
將在每次 state 更新時被調用,這將不斷將StateProvider
的值重置為未來值
// this provider will provide the current value of the counter
final _counterProv = StateProvider((ref) => 0);
class Body extends ConsumerWidget {
const Body({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return ref.watch(_futureCounterProv).when(
loading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
error: (error, stackTrace) {
return Text(error.toString());
},
data: (data) {
Future.microtask(
() {
// Assigning the future value to the `StateProvider`
return ref.read(_counterProv.notifier).state = data;
},
);
return Consumer(
builder: (context, ref, _) {
final count = ref.watch(_counterProv);
return Column(
children: [
IconButton(
onPressed: () {
ref
.read(_counterProv.notifier)
.update((value) => value + 1);
},
icon: const Icon(Icons.add),
),
Text(
count.toString(),
),
],
);
},
);
},
);
}
}
ChangeNotifierProvider
: StateProvider
有 2 個選項來更新其值: value
設置器和update
方法,它們都會觸發重建。 在此解決方法中,我們希望實施不觸發重建的 state 更新。 一種方法是使用ChangeNotifierProvider
而不是StateProvider
。 通過使用ChangeNotifierProvider
,我們可以控制我們自己的更新操作並在需要時調用notifyListeners
(這將觸發重建)。
您必須確保您的ChangeNotifierProvider
依賴項位於updateNoNotify
調用下方的 Consumer 中,否則ChangeNotifierProvider
的依賴項將繼續重置為未來的值。 此外,您還必須確保所有使用此ChangeNotifierProvider
的小部件都在updateNoNotify
下方的小部件樹中,否則它們將不會被重建,因為我們沒有觸發重建
// the new `_counterProv`
final _counterProv = ChangeNotifierProvider(
(ref) => _CounterNotifier(),
);
class _CounterNotifier extends ChangeNotifier {
int _value = 0;
int get value => _value;
void update(int Function(int value) update) {
_value = update(_value);
// trigger a rebuild
notifyListeners();
}
void updateNoNotify(int Function(int value) update) {
_value = update(_value);
}
}
// the ui
class Body extends ConsumerWidget {
const Body({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return ref.watch(_futureCounterProv).when(
loading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
error: (error, stackTrace) {
return Text(error.toString());
},
data: (data) {
// calling `updateNoNotify` which does not trigger
// trigger rebuild as it does not call `notifyListeners`
ref.read(_counterProv.notifier).updateNoNotify(
(e) => data,
);
return Consumer(
builder: (context, ref, _) {
final count = ref.watch(_counterProv).value;
return Column(
children: [
IconButton(
onPressed: () {
ref.read(_counterProv.notifier).update(
(value) => value + 1,
);
},
icon: const Icon(Icons.add),
),
Text(
count.toString(),
),
],
);
},
);
},
);
}
}
這些不是safest
的解決方法,但它們是workaround
,一旦找到安全的方法,我將更新此答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.