Flutter BloC 不刷新我的视图(计数器应用程序)

Flutter BloC not refresh my view (counter app)

我正在尝试使用带有计数器测试应用程序的 BloC 库,但是当我使用对象 increment/decrement 我的计数器时,我的观点有点问题。 MyObject.MyProperty 递增或递减但我的视图未刷新。为什么?

Sample app 带有简单的 int 变量。

我的对象代码:

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

如您所见,我稍微编辑了示例应用程序,只是为了添加我的 class TestTest 和 int 属性 myProperty。当我点击我的按钮时,我的对象中的值发生变化,但我的视图没有刷新。

我该如何解决?

我在 mapEventToState 中找到了重新创建 TestTest 的解决方案,但是重新创建整个对象只是为了更新 属性...

很奇怪

谢谢

我看到您正在使用某种 redux 实现,但我不太确定它在分派操作时如何处理重建。

据我所知,您正在调度更新小部件上的一些 属性 的操作,但您再也不会调用 setState,因此不会重建小部件。

尝试在 setState 函数中调用递增或递减操作。

像这样:

onPressed: () {
 setState(() => counterBloc.dispatch(CounterEvent.decrement));
},

我遇到了同样的问题,在谷歌搜索几个小时后,我在 https://github.com/felangel/bloc/issues/203#issuecomment-480619554

中找到了解决方案

如下代码所示,主要问题是当你yield状态时,前一个状态和当前状态是相等的,所以blocBuilder没有触发。

case CounterEvent.decrement:        
  currentState.myProperty -= 1;
  yield currentState; 

你应该复制状态,然后改变并产生它。

final TestTest newState = TestTest();
newState.myProperty = currentState.myProperty;

...

case CounterEvent.decrement:        
  newState.myProperty -= 1;
  yield newState; 

只是为未来的访客发布另一个可能的解决方案。

如果您对同一个状态执行 yield 两次。您的 UI 不会更新。

例如,如果您已经从您的 Bloc 触发了 ShowDataToUser(data),现在在另一次操作之后您再次产生 ShowDataToUser(data),您的 UI 将不会更新。

一个快速解决这个问题的方法是在你的 Bloc 中创建一个 DummyState() 并且每次在你 yield ShowDataToUser(data)

之前 yield DummyState()

除了快速破解之外的另一个解决方案是为 dart 定义一种比较和等同 class 的方法,因为目前默认 ShowDataToUser 是相同的 class,但是它的 contents 不同,但 Dart 不知道如何评估内容并比较它们。

输入Equatable

为此,您需要使用包:https://pub.dev/packages/equatable

现在您必须使用 Equtable 扩展您的 Bloc 状态,例如:

class DummyState extends Equatable {}

现在,如果您的 Bloc States 正在扩展 Equatable,那么您必须覆盖该函数:

@override
  List<Object> get props => [name];

此处 name 是您在比较两个相同的 class 时要比较的 property/field 名称。

这个函数告诉你的 Bloc,如何区分两个相同的状态(它们可能有不同的值)。