简体   繁体   English

Bloc State 已产生,但 UI 未更新

[英]Bloc State is yielded but UI is not updating

I'm having an issue using bloc.我在使用 bloc 时遇到问题。 The bloc state is updating but it seems to be no effect on UI.块 state 正在更新,但似乎对 UI 没有影响。 I have reproduced the issue using an example app.我已经使用示例应用程序重现了该问题。 The issue is removing an item from the list page does not change is color back to deselected state.问题是从列表页面中删除一个项目不会改变颜色回到取消选择的 state。 Actually what happens is When you select an item on home page the cart button appears and on no items selected state it disappears.实际上发生的情况是当您 select 主页上的一个项目时,购物车按钮会出现,并且在没有选择项目 state 时它会消失。 So when you selected an item on homepage the cart button appears.因此,当您在主页上选择一个项目时,会出现购物车按钮。 When you click on the button you're navigated to another page ie ListPage where you can see the list of all selected items and a remove button corresponding to every item.当您单击该按钮时,您将导航到另一个页面,即 ListPage,您可以在其中看到所有选定项目的列表以及与每个项目对应的删除按钮。 When you remove an item it gets removed from ListPage but still it's color is Red ie selected on HomePage.当您删除一个项目时,它会从 ListPage 中删除,但它的颜色仍然是红色,即在 HomePage 上选中。 I have to click again to change the color although it was deselected ie (item.active = false) on removing it from the ListPage.我必须再次单击以更改颜色,尽管它在从 ListPage 中删除时被取消选择,即 (item.active = false)。 Just the color stays the same, it's not getting updated.只是颜色保持不变,它没有得到更新。 The code files are given below:代码文件如下:

item_bloc.dart item_bloc.dart

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:demo/bloc/cart/cart_bloc.dart';
import 'package:demo/item_model.dart';
import 'package:demo/repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';

part 'items_event.dart';
part 'items_state.dart';

class ItemsBloc extends Bloc<ItemsEvent, ItemsState> {
  final ItemRepository itemRepository;
  final CartBloc cartBloc;

  ItemsBloc({
    @required this.itemRepository,
    @required this.cartBloc,
  }) : super(ItemsLoading());

  @override
  Stream<ItemsState> mapEventToState(
    ItemsEvent event,
  ) async* {
    if (event is GetItems) {
      yield* _mapGetItemsToState(event);
    } else if (event is UpdateItem) {
      yield* _mapUpdateItemToState(event);
    }
  }

  Stream<ItemsState> _mapGetItemsToState(GetItems event) async* {
    yield ItemsLoading();
    try {
      final _items = await itemRepository.loadItems();
      yield ItemsLoaded(items: _items);
      print('Yielded');
    } catch (_) {
      yield ItemsFailure();
    }
  }

  Stream<ItemsState> _mapUpdateItemToState(UpdateItem event) async* {
    try {
      _updateRepositoryItems(event.item);
      if (event.item.active) {
        cartBloc.add(ShowItems());
      } else {
        cartBloc.add(RemoveItem(itemId: event.item.id));
      }
      yield* _mapGetItemsToState(GetItems());
    } catch (_) {
      yield ItemsFailure();
    }
  }

  Item _updateRepositoryItems(Item item) => itemRepository.setItem = item;
}

cart_bloc.dart cart_bloc.dart

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:demo/item_data_model.dart';
import 'package:demo/repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';

part 'cart_event.dart';
part 'cart_state.dart';

class CartBloc extends Bloc<CartEvent, CartState> {
  final ItemRepository itemRepository;

  CartBloc({@required this.itemRepository}) : super(CartLoading());

  @override
  Stream<CartState> mapEventToState(
    CartEvent event,
  ) async* {
    if (event is ShowItems) {
      yield* _mapShowItemsToState(event);
    } else if (event is RemoveItem) {
      yield* _mapRemoveItemToState(event);
    }
  }

  Stream<CartState> _mapShowItemsToState(ShowItems event) async* {
    try {
      final _selectedItems = await itemRepository.getSelectedItems;

      if (_selectedItems.isNotEmpty) {
        final data = ItemData(items: _selectedItems);

        yield CartLoaded(itemData: data);
      } else {
        yield CartLoading();
      }
    } catch (_) {
      yield CartFailure();
    }
  }

  Stream<CartState> _mapRemoveItemToState(RemoveItem event) async* {
    try {
      final _selectedSounds = await itemRepository.getSelectedItems;

      if (_selectedSounds.isEmpty) {
        yield CartLoading();
      } else {
        yield* _mapShowItemsToState(ShowItems());
      }
    } catch (_) {
      yield CartFailure();
    }
  }
}

homepage.dart主页.dart

import 'package:demo/bloc/cart/cart_bloc.dart';
import 'package:demo/bloc/items/items_bloc.dart';
import 'package:demo/item_tile.dart';
import 'package:demo/list_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
          centerTitle: true,
        ),
        body: Column(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: BlocBuilder<ItemsBloc, ItemsState>(
                  // ignore: missing_return
                  builder: (context, state) {
                    if (state is ItemsLoading) {
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    } else if (state is ItemsLoaded) {
                      print('Items Loaded');
                      return GridView.count(
                        crossAxisCount: 3,
                        crossAxisSpacing: 20.0,
                        mainAxisSpacing: 20.0,
                        childAspectRatio: 0.6,
                        children: [
                          for (var item in state.items) ItemTile(item: item),
                        ],
                      );
                    } else if (state is ItemsFailure) {
                      return Center(
                        child: Text(
                          'Unexpected Failure, Cannot Load Items',
                          style: Theme.of(context).textTheme.headline6,
                        ),
                      );
                    }
                  },
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: CartButton(),
            ),
          ],
        ),
      ),
    );
  }
}

class CartButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<CartBloc, CartState>(
      // ignore: missing_return
      builder: (context, state) {
        if (state is CartLoading) {
          return SizedBox.shrink();
        } else if (state is CartLoaded) {
          print('Cart Loaded');
          return TextButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) {
                  return ListPage(
                    items: state.itemData.items,
                  );
                }),
              );
            },
            child: Text('Go To Cart'),
          );
        } else if (state is CartFailure) {
          return Center(
            child: Text(
              'Unexpected Failure, Cannot Load Cart',
              style: Theme.of(context).textTheme.headline6,
            ),
          );
        }
      },
    );
  }
}

item_tile.dart item_tile.dart

import 'package:demo/bloc/items/items_bloc.dart';
import 'package:demo/get_it.dart';
import 'package:demo/item_model.dart';
import 'package:flutter/material.dart';

class ItemTile extends StatefulWidget {
  final Item item;

  const ItemTile({Key key, this.item}) : super(key: key);
  @override
  _ItemTileState createState() => _ItemTileState();
}

class _ItemTileState extends State<ItemTile> {
  bool active;

  @override
  void initState() {
    super.initState();
    active = widget.item.active;
  }

  void _onItemTap() {
    setState(() {
      active = !active;
    });

    getIt<ItemsBloc>()
        .add(UpdateItem(item: widget.item.copyWith(active: active)));
  }

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(widget.item.title),
      tileColor: active ? Colors.redAccent : Colors.blueAccent,
      onTap: () {
        _onItemTap();
      },
    );
  }
}

item_page.dart item_page.dart

import 'package:demo/bloc/items/items_bloc.dart';
import 'package:demo/get_it.dart';
import 'package:flutter/material.dart';

import 'item_model.dart';

class ListPage extends StatefulWidget {
  final List<Item> items;

  const ListPage({Key key, this.items}) : super(key: key);
  @override
  _PlayerScreenState createState() => _PlayerScreenState();
}

class _PlayerScreenState extends State<ListPage> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text(
            'Cart List Page',
            style: Theme.of(context).textTheme.headline6,
          ),
          centerTitle: true,
        ),
        body: Padding(
          padding: const EdgeInsets.all(12.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: ListView.separated(
                  itemCount: widget.items.length,
                  separatorBuilder: (BuildContext context, int index) =>
                      Divider(),
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      trailing: IconButton(
                        icon: Icon(
                          Icons.close_rounded,
                          color: Colors.black,
                        ),
                        onPressed: () {
                          getIt<ItemsBloc>().add(UpdateItem(
                            item: widget.items.elementAt(index).copyWith(
                                active: !widget.items.elementAt(index).active),
                          ));

                          setState(() {
                            widget.items.removeAt(index);
                          });
                          if (widget.items.isEmpty) {
                            Navigator.pop(context);
                          }
                        },
                      ),
                      title: Text(
                        widget.items.elementAt(index).title,
                      ),
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

get_it.dart get_it.dart

import 'package:demo/bloc/cart/cart_bloc.dart';
import 'package:demo/bloc/items/items_bloc.dart';
import 'package:demo/repository.dart';
import 'package:get_it/get_it.dart';

final getIt = GetIt.instance;

Future<void> init() async {
  // Bloc

  getIt.registerLazySingleton<CartBloc>(() => CartBloc(itemRepository: getIt()));

  getIt.registerFactory(() => ItemsBloc(
        itemRepository: getIt(),
        cartBloc: getIt(),
      ));

  // Repository
  getIt.registerSingleton<ItemRepository>(ItemRepository());
}

main.dart main.dart

import 'package:demo/bloc/cart/cart_bloc.dart';
import 'package:demo/bloc/items/items_bloc.dart';
import 'package:demo/get_it.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'get_it.dart' as di;
import 'package:flutter/material.dart';

import 'home_page.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  di.init();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => getIt<ItemsBloc>()..add(GetItems()),
        ),
        BlocProvider(
          create: (context) => getIt<CartBloc>(),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomePage(),
      ),
    );
  }
}

Down Here are the images of the issue:下面是问题的图片:

主页

列表页面

Ok, so based on the comments, that indicates that you're already in an ItemsLoaded state when removing the item.好的,根据评论,这表明您在删除项目时已经在ItemsLoaded state 中。 Since it's not a new state, then a rebuild is not triggered.由于它不是新的 state,因此不会触发重建。 So it's behaving as expected.所以它的行为符合预期。 Looks like you need to rethink how you do this, perhaps by yielding an ItemsUpdated state before then yielding the ItemsLoaded state.看起来您需要重新考虑如何执行此操作,也许通过在产生ItemsUpdated state 之前产生ItemsLoaded state。

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

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