[英]Flutter BloC not refresh my view (counter app)
I'm trying BloC library with Counter test app but I have a little problem on my view when I use object to increment/decrement my counter.我正在尝试使用计数器测试应用程序使用 BloC 库,但是当我使用对象来增加/减少我的计数器时,我的视图有一些问题。 MyObject.MyProperty increment or decrement but my view not refreshed. MyObject.MyProperty 增加或减少但我的视图没有刷新。 Why?为什么?
Sample app with simple int variable.带有简单 int 变量的示例应用程序。
My code with object:我的对象代码:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: BlocProvider(
builder: (context) => CounterBloc(),
child: CounterPage(),
),
);
}
}
class TestTest{
int myProperty;
TestTest(){
myProperty = 0;
}
}
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
@override
Widget build(BuildContext context) {
final counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterBloc, TestTest>(
builder: (context, myClassTestTest) {
return Center(
child: Text(
'${myClassTestTest.myProperty}',
style: TextStyle(fontSize: 24.0),
),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
counterBloc.dispatch(CounterEvent.increment);
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
counterBloc.dispatch(CounterEvent.decrement);
},
),
),
],
),
);
}
}
enum CounterEvent { increment, decrement }
class CounterBloc extends Bloc<CounterEvent, TestTest> {
@override
TestTest get initialState => TestTest();
@override
Stream<TestTest> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.decrement:
currentState.myProperty -= 1;
yield currentState;
break;
case CounterEvent.increment:
currentState.myProperty += 1;
yield currentState;
break;
}
}
}
As you can see I edited the sample app a little just to add my class TestTest
with a int property myProperty
.正如您所看到的,我对示例应用程序进行了一些编辑,只是为了添加带有 int 属性myProperty
类TestTest
。 When I clic on my button the value in my object change but my view is not refreshed.当我点击我的按钮时,我的对象中的值会发生变化,但我的视图没有刷新。
How can I fix that?我该如何解决?
I found a solution to recreate my TestTest in mapEventToState
but it's weird to recreate an entire object just to update a property...我找到了在mapEventToState
重新创建我的 TestTest 的解决方案,但是重新创建整个对象只是为了更新属性很奇怪......
Thank you谢谢
Just posting another possible solution for future visitors.只是为未来的访问者发布另一个可能的解决方案。
If you do yield
for the same state twice.如果您确实两次yield
同一个状态。 Your UI won't update.您的用户界面不会更新。
For example if you have already triggered ShowDataToUser(data)
from your Bloc and now after another operation you are yielding ShowDataToUser(data)
again, your UI won't update.例如,如果您已经从您的 Bloc 触发了ShowDataToUser(data)
并且现在在另一个操作之后您再次产生ShowDataToUser(data)
,则您的 UI 将不会更新。
A quick hack around this would be to just create a DummyState()
in your Bloc and yield DummyState()
everytime before you yield ShowDataToUser(data)
一个快速解决这个问题的方法是在你的 Bloc 中创建一个DummyState()
在每次产生ShowDataToUser(data)
之前产生DummyState()
ShowDataToUser(data)
Another solution apart from the quick hack around is to define a way for dart to compare and equate a class, cos currently by default ShowDataToUser
is the same class, but its contents
are different, but Dart doesn't know how to evaluate the content and compare them.除了快速破解之外的另一个解决方案是定义一种让 dart 比较和等同的方法,因为目前默认情况下ShowDataToUser
是同一个类,但其contents
不同,但 Dart 不知道如何评估内容和比较它们。
Enters Equatable
进入Equatable
For this, you need to use the package : https://pub.dev/packages/equatable为此,您需要使用包: https : //pub.dev/packages/equatable
Now you have to extend your Bloc states with Equtable like:现在您必须使用 Equtable 扩展您的 Bloc 状态,例如:
class DummyState extends Equatable {}
Now, if your Bloc States are extending Equatable then you must override the function:现在,如果您的 Bloc States 正在扩展 Equatable,那么您必须覆盖该函数:
@override
List<Object> get props => [name];
Here name
is the property/field name you want to compare when comparing two same classes.这里的name
是比较两个相同类时要比较的属性/字段名称。
This function tells your Bloc, how to differentiate between two same states (which might have different values in them).这个函数告诉你的 Bloc,如何区分两个相同的状态(它们可能有不同的值)。
I see you are using some kind of redux implementation and i'm not quite sure how this handles the rebuild when actions are dispatched.我看到您正在使用某种 redux 实现,我不太确定这在调度操作时如何处理重建。
As my knowledge you are dispatching an action that update some property on the widget but you are never calling setState again, so the widget is not being rebuild.据我所知,您正在调度更新小部件上某些属性的操作,但您永远不会再次调用 setState,因此不会重建小部件。
Try to call the increment or decrement actions inside a setState function.尝试在 setState 函数中调用增量或减量操作。
Something like this:像这样的东西:
onPressed: () {
setState(() => counterBloc.dispatch(CounterEvent.decrement));
},
I have had same problem, and after googling couple of hour, I have found the solution in https://github.com/felangel/bloc/issues/203#issuecomment-480619554我遇到了同样的问题,在谷歌搜索几个小时后,我在https://github.com/felangel/bloc/issues/203#issuecomment-480619554 中找到了解决方案
As shown in the below code, The main problem is that when you yield the state, the previous state and the current state are equal, so blocBuilder have hadn't triggered.如下代码所示,主要的问题是当你yield state时,之前的状态和当前的状态是相等的,所以blocBuilder还没有触发。
case CounterEvent.decrement:
currentState.myProperty -= 1;
yield currentState;
You should copy the state, then change and yield it.您应该复制状态,然后更改并生成它。
final TestTest newState = TestTest();
newState.myProperty = currentState.myProperty;
...
case CounterEvent.decrement:
newState.myProperty -= 1;
yield newState;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.