Flutter_bloc: ^8.0.0 State 在使用不同的 props 发出相同状态时不会重建

Flutter_bloc: ^8.0.0 State does not rebuild when emitting the same state with different props

我正在试验状态管理原型,最近偶然发现了一个问题。问题是一次交互确实会重新加载屏幕,这很好。虽然另一个交互不会重新加载屏幕,即使它发出相同的状态(也改变了 prop)。

我的原型有 3 个屏幕:

  1. 一个列表视图(https://i.stack.imgur.com/bI9K6.png)
  2. 列表项的详细信息页面 (https://i.stack.imgur.com/DByDn.png)
  3. 表格 (https://i.stack.imgur.com/s8ltv.png)

屏幕截图中的星星在下面的小部件中表示:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:state_management/models/product/product.dart';
import 'package:state_management/models/product/product_bloc.dart';
class RatingBox extends StatefulWidget {
    final Product item;
    RatingBox({
        Key ? key, required this.item
    }): super(key: key);@
    override
    _RatingBoxState createState() {
        return _RatingBoxState();
    }
}
class _RatingBoxState extends State < RatingBox > {@
    override
    Widget build(BuildContext context) {
        double _size = 20;
        return Row(
            mainAxisAlignment: MainAxisAlignment.end,
            crossAxisAlignment: CrossAxisAlignment.end,
            mainAxisSize: MainAxisSize.max,
            children: [
                for (int i = 1; i <= 3; i++)
                    Container(
                        padding: const EdgeInsets.all(0),
                        child: IconButton(
                            icon: (widget.item.rating >= i ? Icon(
                                Icons.star,
                                size: _size,
                            ) : Icon(
                                Icons.star_border,
                                size: _size,
                            )),
                            color: Colors.red[500],
                            onPressed: () {
                                context.read < ProductBloc > ().add(UpdateProductRating(
                                    product: widget.item.copyWith(rating: i)));
                            },
                            iconSize: _size,
                        ),
                    ),
            ],
        );
    }
}

使用另一个事件(出于测试目的)通过提交按钮更新表单。但它里面有相同的代码:

context.read < ProductBloc > ().add(UpdateProduct(
    product: item.copyWith(
        name: item.name,
        description: item.description,
        price: item.price)));

下面的代码是product_bloc、product_event和product_state的代码:

class ProductBloc extends Bloc < ProductEvent, ProductState > {
    ProductBloc(): super(ProductLoading()) {
        on < LoadProduct > (_onLoadProduct);
        on < UpdateProduct > (_onUpdateProduct);
        on < UpdateProductRating > (_onUpdateProductRating);
    }
    void _onLoadProduct(LoadProduct event, Emitter < ProductState > emit) {
        print('load');
        emit(
            ProductLoaded(products: event.products),
        );
    }
    void _onUpdateProductRating(
        UpdateProductRating event, Emitter < ProductState > emit) {
        final state = this.state;
        if (state is ProductLoaded) {
            print('updateRating');
            List < Product > products = (state.products.map((product) {
                return product.id == event.product.id ? event.product : product;
            })).toList();
            emit(ProductLoaded(products: List.of(products)));
        }
    }
    void _onUpdateProduct(UpdateProduct event, Emitter < ProductState > emit) {
        final state = this.state;
        if (state is ProductLoaded) {
            print('update');
            List < Product > products = (state.products.map((product) {
                return product.id == event.product.id ? event.product : product;
            })).toList();
            emit(ProductLoaded(products: products));
        }
    }
}
abstract class ProductEvent extends Equatable {
    const ProductEvent();@
    override
    List < Object > get props = > [];
}
class LoadProduct extends ProductEvent {
    final List < Product > products;
    const LoadProduct({
        this.products = const < Product > []
    });@
    override
    List < Object > get props = > [products];
}
class UpdateProduct extends ProductEvent {
    final Product product;
    const UpdateProduct({
        required this.product
    });@
    override
    List < Object > get props = > [product];
}
class UpdateProductRating extends ProductEvent {
    final Product product;
    const UpdateProductRating({
        required this.product
    });@
    override
    List < Object > get props = > [product];
}
abstract class ProductState extends Equatable {
    const ProductState();@
    override
    List < Object > get props = > [];
}
class ProductLoading extends ProductState {}
class ProductLoaded extends ProductState {
    final List < Product > products;
    const ProductLoaded({
        this.products = const < Product > []
    });@
    override
    List < Object > get props = > [products];
}

最重要的部分是设置星星 而更改下一页的表格 不会 达到目的。奇怪的是,如果我在发出我希望应用程序处于的状态之前发出另一个状态,它会改变。

我希望这对大家有意义。这是我在 Whosebug 上的第一个 post,非常感谢您的反馈!

我找到问题了!

我过早地设置了我的项目属性,这导致 BLoC 无法识别更改,因为正在设置的是同一产品。

因此,不要在 onChange 事件中设置 item.xx,而是尝试将结果存储在另一个地方,例如 TextEditingController。然后在提交表单时,使用存储的数据创建一个新对象,该对象将被识别为更改。