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 个屏幕:
- 一个列表视图(https://i.stack.imgur.com/bI9K6.png)
- 列表项的详细信息页面 (https://i.stack.imgur.com/DByDn.png)
- 表格 (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。然后在提交表单时,使用存储的数据创建一个新对象,该对象将被识别为更改。
我正在试验状态管理原型,最近偶然发现了一个问题。问题是一次交互确实会重新加载屏幕,这很好。虽然另一个交互不会重新加载屏幕,即使它发出相同的状态(也改变了 prop)。
我的原型有 3 个屏幕:
- 一个列表视图(https://i.stack.imgur.com/bI9K6.png)
- 列表项的详细信息页面 (https://i.stack.imgur.com/DByDn.png)
- 表格 (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。然后在提交表单时,使用存储的数据创建一个新对象,该对象将被识别为更改。