如何在 Riverpod 中显示来自 StateNotifier 的小吃店?
Posted
技术标签:
【中文标题】如何在 Riverpod 中显示来自 StateNotifier 的小吃店?【英文标题】:How do I show a snackbar from a StateNotifier in Riverpod? 【发布时间】:2021-05-24 18:44:07 【问题描述】:我的以下课程运行良好。
class CartRiverpod extends StateNotifier<List<CartItemModel>>
CartRiverpod([List<CartItemModel> products]) : super(products ?? []);
void add(ProductModel addProduct)
bool productExists = false;
for (final product in state)
if (product.id == addProduct.id)
print("not added");
productExists = true;
else
if (productExists==false)
state = [
...state, new CartItemModel(product: addProduct),
];
print("added");
void remove(String id)
state = state.where((product) => product.id != id).toList();
上面的代码完美运行。在我的购物车中,我想将产品的订单限制为 1 个单位,这就是我执行上面代码的原因。它按我的预期工作。 现在唯一的事情是,我想显示一个快餐栏,提醒用户他或她只能订购每种产品的 1 个单位。
如何在我的 StateNotifier 中添加一个快餐栏?
【问题讨论】:
【参考方案1】:import 'package:flutter/material.dart';
import 'package:flutter_riverpod/all.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'cart_list_page.freezed.dart';
final cartListPageStateNotifierProvider =
StateNotifierProvider((ref) => CartListPageStateNotifier(ref.read));
final cartListProvider = StateProvider((ref)
return <CartListItemModel>[];
); // this holds the cart list, at initial, its empty
class CartListPage extends StatefulWidget
@override
_CartListPageState createState() => _CartListPageState();
class _CartListPageState extends State<CartListPage>
final _scaffoldKey = GlobalKey<ScaffoldState>();
List<CartListItemModel> productsToBeAddedToCart = [
CartListItemModel(id: 1, name: "Apple"),
CartListItemModel(id: 2, name: "Tomatoes"),
CartListItemModel(id: 3, name: "Oranges"),
CartListItemModel(id: 4, name: "Ginger"),
CartListItemModel(id: 5, name: "Garlic"),
CartListItemModel(id: 6, name: "Pine"),
];
@override
Widget build(BuildContext context)
return ProviderListener<CartListState>(
provider: cartListPageStateNotifierProvider.state,
onChange: (context, state)
return state.maybeWhen(
loading: ()
final snackBar = SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.yellow,
content: Text('updating cart....'),
);
return _scaffoldKey.currentState.showSnackBar(snackBar);
,
success: (info)
final snackBar = SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.green,
content: Text('$info'),
);
_scaffoldKey.currentState.hideCurrentSnackBar();
return _scaffoldKey.currentState.showSnackBar(snackBar);
,
error: (errMsg)
final snackBar = SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
content: Text('$errMsg'),
);
_scaffoldKey.currentState.hideCurrentSnackBar();
return _scaffoldKey.currentState.showSnackBar(snackBar);
,
orElse: () => SizedBox.shrink(),
);
,
child: Scaffold(
key: _scaffoldKey,
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
SizedBox(height: 40),
Expanded(
child: ListView.builder(
itemCount: productsToBeAddedToCart.length,
itemBuilder: (context, index)
final item = productsToBeAddedToCart[index];
return ListTile(
title: Text("$item.name"),
leading: CircleAvatar(child: Text("$item.id")),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => context
.read(cartListPageStateNotifierProvider)
.addProduct(item),
),
SizedBox(width: 2),
IconButton(
icon: Icon(Icons.remove),
onPressed: () => context
.read(cartListPageStateNotifierProvider)
.removeProduct(item),
),
],
),
);
,
),
)
],
),
),
),
);
class CartListPageStateNotifier extends StateNotifier<CartListState>
final Reader reader;
CartListPageStateNotifier(this.reader) : super(CartListState.initial());
addProduct(CartListItemModel product) async
state = CartListState.loading();
await Future.delayed(Duration(seconds: 1));
var products = reader(cartListProvider).state;
if (!products.contains(product))
reader(cartListProvider).state.add(product);
return state =
CartListState.success("Added Successfully $product.name");
else
return state = CartListState.error(
"cannot add more than 1 product of the same kind");
removeProduct(CartListItemModel product) async
state = CartListState.loading();
await Future.delayed(Duration(seconds: 1));
var products = reader(cartListProvider).state;
if (products.isNotEmpty)
bool status = reader(cartListProvider).state.remove(product);
if (status)
return state =
CartListState.success("removed Successfully $product.name");
else
return state;
return state = CartListState.error("cart is empty");
@freezed
abstract class CartListState with _$CartListState
const factory CartListState.initial() = _CartListInitial;
const factory CartListState.loading() = _CartListLoading;
const factory CartListState.success([String message]) = _CartListSuccess;
const factory CartListState.error([String message]) = _CartListError;
@freezed
abstract class CartListItemModel with _$CartListItemModel
factory CartListItemModel(final String name, final int id) =
_CartListItemModel;
【讨论】:
对不起,我有点过火了。要运行此代码,您需要 build_runner,因为我使用了 freezed。安装:冻结的 build_runner 命令:flutter pub run build_runner build ProviderListener 已被弃用,ref.listen 现在是根据 Riverpod 的文档在发生错误时显示快餐栏的推荐方式。【参考方案2】:不要在此处显示小吃店。 您需要在小部件树中侦听所需的值,如下所示:
@override
Widget build(BuildContext context, WidgetRef ref)
ref.listen(cartListPageStateNotifierProvider, (value)
// show snackbar here...
);
...
【讨论】:
以上是关于如何在 Riverpod 中显示来自 StateNotifier 的小吃店?的主要内容,如果未能解决你的问题,请参考以下文章
RiverPod - 如何在不在小部件中的 AsyncValue 上等待使用 FutureProvider
Riverpod - 如何在消费者中包装 PreferredSizeWidget
使用 RiverPod 状态管理 Flutter 更改 Text 值