flutter - 更新同级状态(数据)flutter bloc
问题描述
我正在尝试更新最初已经加载数据的同级小部件中的数据。第二个小部件添加到相同的数据并同时获取它,显示更新的数据。新数据不会反映在第一个小部件中。以购物车和商品数量为例。当我在购物车中添加新商品或更改数量时,它不会反映在购物车中。所有数据都在 django rest api 中远程调用。如果我重新加载应用程序,新数据会显示在购物车中。
这是我要更改其中数据的小部件
class MainScreen extends StatefulWidget {
final TokenResponse token;
const MainScreen({Key key, this.token});
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
BottomNavBarBloc _bottomNavBarBloc;
CartBloc cartBloc;
@override
void initState() {
_bottomNavBarBloc = BottomNavBarBloc();
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
cartBloc = BlocProvider.of<CartBloc>(context);
cartBloc.add(FetchOrderSummaryEvent());
return Scaffold(
backgroundColor: Colors.white,
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
sized: false,
child: StreamBuilder<NavBarItem>(
stream: _bottomNavBarBloc.itemStream,
initialData: _bottomNavBarBloc.defaultItem,
builder:
(BuildContext context, AsyncSnapshot<NavBarItem> snapshot) {
switch (snapshot.data) {
case NavBarItem.HOME:
return HomeScreen();
case NavBarItem.OFFERS:
return OffersScreen();
case NavBarItem.REWARDS:
return _testScreen();
case NavBarItem.FAVORITE:
return _testScreen();
case NavBarItem.BAG:
return CartScreen();
case NavBarItem.ACCOUNT:
return AccountMainScreen();
}
return Container();
}),
),
bottomNavigationBar: StreamBuilder(
stream: _bottomNavBarBloc.itemStream,
initialData: _bottomNavBarBloc.defaultItem,
builder: (BuildContext context, AsyncSnapshot<NavBarItem> snapshot) {
return BottomNavigationBar(
unselectedItemColor: Style.Colors.secondaryColor,
selectedItemColor: Style.Colors.primaryColor,
backgroundColor: Colors.white,
selectedFontSize: 10.0,
unselectedFontSize: 10.0,
type: BottomNavigationBarType.fixed,
currentIndex: snapshot.data.index,
onTap: _bottomNavBarBloc.pickItem,
items: [
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: Text("Home"),
),
icon: Icon(
FontAwesomeIcons.bars,
color: Style.Colors.secondaryColor,
),
activeIcon: Icon(
FontAwesomeIcons.bars,
color: Style.Colors.primaryColor,
)),
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: Text("Offers"),
),
icon: Icon(
FontAwesomeIcons.tag,
color: Style.Colors.secondaryColor,
),
activeIcon: Icon(
FontAwesomeIcons.tag,
color: Style.Colors.primaryColor,
)),
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: Text("Rewards"),
),
icon: Icon(
FontAwesomeIcons.gift,
color: Style.Colors.secondaryColor,
),
activeIcon: Icon(
FontAwesomeIcons.gift,
color: Style.Colors.primaryColor,
)),
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: Text("Favorite"),
),
icon: Icon(
FontAwesomeIcons.heart,
color: Style.Colors.secondaryColor,
),
activeIcon: Icon(
FontAwesomeIcons.heart,
color: Style.Colors.primaryColor,
)),
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: Text("Bag"),
),
icon: Container(
width: 30,
height: 25,
child: Stack(children: <Widget>[
Icon(
FontAwesomeIcons.shoppingBag,
color: Style.Colors.secondaryColor,
),
BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is AuthenticationAuthenticated) {
return BlocBuilder<CartBloc, CartState>(
builder: (context, state) {
if (state is CartLoaded) {
print("loaded ${state.order.totalItemQuantity}"); // <=== change this data
return Positioned(
right: 0,
top: 0,
child: Container(
height: 20.0,
width: 20.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
border: Border.all(
width: 1.0,
color: Colors.white,
),
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
left: 1.0,
bottom: 1.0,
),
child: Text(
state.order.totalItemQuantity !=null? state.order.totalItemQuantity.toString():"",
style: TextStyle(
color: Colors.white,
fontSize: 10.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
} else {
return Container(
);
}
},
);
} else {
return Text(" ");
}
},
)
]),
),
activeIcon: Container(
width: 30,
height: 25,
child: Stack(children: <Widget>[
Icon(
FontAwesomeIcons.shoppingBag,
color: Style.Colors.primaryColor,
),
BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is AuthenticationAuthenticated) {
return BlocBuilder<CartBloc, CartState>(
builder: (context, state) {
if (state is CartLoaded) {
print("loaded ${state.order.totalItemQuantity}");
return Positioned(
right: 0,
top: 0,
child: Container(
height: 20.0,
width: 20.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
border: Border.all(
width: 1.0,
color: Colors.white,
),
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
left: 1.0,
bottom: 1.0,
),
child: Text(
state.order.totalItemQuantity !=null? state.order.totalItemQuantity.toString():"",
style: TextStyle(
color: Colors.white,
fontSize: 10.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
} else {
return Container(
);
}
},
);
} else {
return Text(" ");
}
},
)
]),
),),
BottomNavigationBarItem(
title: Padding(
padding: EdgeInsets.only(top: 5.0),
child: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is AuthenticationAuthenticated) {
return Text("Account");
} else {
return Text("Login");
}
},
),
),
icon: Icon(
FontAwesomeIcons.user,
color: Style.Colors.secondaryColor,
),
activeIcon: Icon(
FontAwesomeIcons.user,
color: Style.Colors.primaryColor,
)),
],
);
},
),
);
}
Widget _testScreen() {
return Center(
child: Text(
'Test Screen',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
fontSize: 25.0,
),
),
);
}
}
我在这里调用同级小部件中的 API 我发布了从同级小部件按下按钮后调用的处理方法:
handleAddItemFromCart(
String slug, List<ItemVariations> itemVariations, BuildContext context) {
final cartBloc = BlocProvider.of<CartBloc>(context);
final currentState = cartBloc.state;
if( currentState is CartLoaded){
print("order quantity: ${currentState.order.totalItemQuantity.toString()}");
}
print("current state " + currentState.toString());
cartBloc.add(AddItemToCartEvent(
slug: slug, variations: formatVariations(itemVariations)));
cartBloc.add(FetchOrderSummaryEvent());
}
cart_event.dart
@immutable
abstract class CartEvent extends Equatable {
CartEvent([List props = const []]):super();
}
class FetchOrderSummaryEvent extends CartEvent {
FetchOrderSummaryEvent([List props = const[]]) : super(props);
Order order;
@override
List<Object> get props => [this.order];
}
class RemoveItemFromCartEvent extends CartEvent {
String slug;
List<int> variations;
RemoveItemFromCartEvent({@required this.slug, this.variations});
@override
List<Object> get props => [];
}
class AddItemToCartEvent extends CartEvent {
String slug;
List<int> variations;
AddItemToCartEvent({@required this.slug, @required this.variations});
@override
List<Object> get props => [];
}
class RemoveItemEvent extends CartEvent {
@override
List<Object> get props => [];
}
class CheckoutEvent extends CartEvent {
String stripeToken;
int selectedAddress;
CheckoutEvent({@required this.stripeToken, @required this.selectedAddress});
@override
List<Object> get props => [];
}
cart_state.dart
@immutable
abstract class CartState extends Equatable {
CartState([List props = const[]]):super();
@override
List<Object> get props => [];
}
class CartInitial extends CartState {
@override
// TODO: implement props
List<Object> get props => [];
}
class CartLoading extends CartState {
@override
// TODO: implement props
List<Object> get props => [];
}
class CartLoaded extends CartState {
Order order;
CartLoaded({@required this.order});
CartLoaded copyWith({Order order}) {
return CartLoaded(order: order ?? this.order);
}
@override
// TODO: implement props
List<Object> get props => [order];
}
class CartFailure extends CartState {
String message;
CartFailure({@required this.message});
@override
// TODO: implement props
List<Object> get props => [message];
}
cart_bloc.dart:
class CartBloc extends Bloc<CartEvent, CartState> {
MenuItemsRepository menuItemsRepository;
CartBloc({@required this.menuItemsRepository});
@override
// TODO: implement initialState
CartState get initialState => CartInitial();
@override
Stream<CartState> mapEventToState(CartEvent event) async* {
final currentState = state;
if (event is FetchOrderSummaryEvent) {
yield CartLoading();
try {
Order order = await menuItemsRepository.getOrder();
yield CartLoaded(order: order);
} catch (err) {
yield CartFailure(message: err.message);
}
}
if (event is AddItemToCartEvent) {
//yield CartLoading();
try {
await menuItemsRepository.addItemToCart(event.slug, event.variations);
} catch (err) {
yield CartFailure(message: err.toString());
}
}
if (event is RemoveItemFromCartEvent) {
yield CartLoading();
try {
await menuItemsRepository.removeItemFromCart(
event.slug, event.variations);
} catch (err) {
yield CartFailure(message: err.toString());
}
}
if (event is CheckoutEvent) {
yield CartLoading();
try {
print("token: ${event.stripeToken}");
await menuItemsRepository.makePayment(
event.stripeToken, event.selectedAddress);
} catch (err) {
yield CartFailure(message: err.toString());
}
}
}
}
存储库:
Future<bool> addItemToCart(String slug, List<int> variations) async {
final token = "Token " + await storage.read(key: utils.TOKEN);
var params = {
"slug": slug,
"variations": variations,
};
try {
Response response = await _dio.post(getAddToCartURL,
data: jsonEncode(params),
options: Options(headers: {
HttpHeaders.authorizationHeader: token,
HttpHeaders.contentTypeHeader: "application/json",
}));
return response.statusCode == 200;
} catch (error, stackTrace) {
print("Exception occurred: $error stackTrace: $stackTrace");
return false;
}
}
Future<Order> getOrder() async {
final token = "Token " + await storage.read(key: utils.TOKEN);
var params = {
"api_key": apiKey,
};
try {
Response response = await _dio.get(getOrderSummaryURL,
queryParameters: params,
options: Options(headers: {
HttpHeaders.authorizationHeader: token,
HttpHeaders.contentTypeHeader: "application/json",
}));
print(response.data);
return Order.fromJson(response.data);
} catch (error, stackTrace) {
print("Exception occurred: $error stackTrace: $stackTrace");
return Order.withError(error.toString());
}
}
解决方案
更新:我想通了!集团 CartBloc 实例化了 2 次!一个在应用程序创建开始或在 main.dart 文件中开始,然后另一个在子小部件中,即 order_summary 文件。这导致无法强制父小部件从 api 获取数据。所以所有更新都是在子级而不是父级中完成的。我希望这会帮助任何可能面临同样问题的人。确保您只实例化 bloc 一次,以便您可以更新或接收来自同一个 bloc 的更新。
推荐阅读
- machine-learning - 二元和分类交叉熵的不同结果
- opengl - 如何在片段着色器中实现折射光?
- python - Python Pandas - 将从函数返回的元组保存到 2 个单独的列中
- c# - 错误:模板的内容不遵循架构
- r - 是否有 MASS:: as.fractions 的文档?
- arrays - 使用转置公式谷歌表格对多行求和
- flask - 烧瓶会话丢失数据
- refresh - 松树编辑器中实时市场中的枢轴点自动刷新
- c - 如何使用互斥锁和/或条件变量同步 2 个 pthread 以创建“猜数字”迷你游戏?
- javascript - JQuery onclick div hide/show/reset for next time clicked