简体   繁体   English

更新兄弟 state(数据)flutter bloc

[英]update sibling state (data) flutter bloc

I am trying to update data in a sibling widget which already loaded data at first.我正在尝试更新最初已经加载数据的同级小部件中的数据。 The second widget adds to the same data and fetches it at the same time showing an updated data.第二个小部件添加到相同的数据并同时获取它,显示更新的数据。 The new data is not reflected in the first widget.新数据不会反映在第一个小部件中。 Take a shopping cart and quantity of items as an example.以购物车和商品数量为例。 When I add new items or change quantities in the cart it does not reflect in the cart.当我在购物车中添加新商品或更改数量时,它不会反映在购物车中。 All data is remotely called in a django rest api.所有数据都在 django rest api 中远程调用。 If I reload the app the new data shows in the cart.如果我重新加载应用程序,新数据会显示在购物车中。

this is the widget where i want to change the data in it这是我要更改其中数据的小部件

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,
        ),
      ),
    );
  }
}

i call the API in a sibling widget here i am posting the handling method that was called after pressing a button from a sibling widget:我在同级小部件中调用 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 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 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: 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());
      }
    }
  }
}

repository:存储库:

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());
    }
  }

UPDATE: i figured it out.更新:我想通了。 the bloc CartBloc was instantiating 2 times. bloc CartBloc 实例化了 2 次。 one at the beginning of the app creation or start in the main.dart file and then another one in a child widget which was the order_summary file.一个在应用程序创建开始时或从 main.dart 文件开始,然后另一个在子小部件中,即 order_summary 文件。 This was was causing to not be able to force the parent widget fetch the data from api.这导致无法强制父小部件从 api 获取数据。 so all the updates was done in the child level not the parent.所以所有更新都是在子级而不是父级中完成的。 I hope this would help anyone who might face the same issue.我希望这会帮助任何可能面临同样问题的人。 Make sure you instantiate the bloc once only so you can update or receive the updates from the same bloc.确保您只实例化 bloc 一次,以便您可以更新或接收来自同一个 bloc 的更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM