【问题标题】:Listen to changes without caring about state in Flutter Bloc在 Flutter Bloc 中监听变化而不关心状态
【发布时间】:2022-10-23 17:05:00
【问题描述】:

我目前正在学习如何在 Flutter 中使用 Bloc 状态管理库,并且我有一个场景,我想收听执行的操作(例如单击按钮)并在小部件树下的子小部件中对该动作做出反应一肘。从文档来看,重建子小部件的唯一方法似乎是存储一个状态对象并对状态的变化做出反应。但是在我的情况下,我不需要存储任何状态,我只想知道一个动作是否已经完成并在每次调用它时做出反应。

鉴于下面的这个例子,我希望WidgetBWidgetA 中的按钮被按下时重建,但我不知道如何构造我的 Cubit 以在不存储某种状态对象的情况下允许它。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// What should the code be here if I don't want to store any state?
class WidgetACubit extends Cubit<void> {
  WidgetACubit({initialState}) : super(initialState);

  void doSomething() => emit(null);
}

class App extends StatelessWidget {
  App({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: BlocProvider(
          create: (_) => WidgetACubit(),
          child: WidgetA(),
        ),
      ),
    );
  }
}

class WidgetA extends StatelessWidget {
  WidgetA({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: () {
            BlocProvider.of<WidgetACubit>(context).doSomething();
            print("Something has been done");
            WidgetB.count++;
          },
          child: const Text("Press me to do something"),
        ),
        WidgetB(),
      ],
    );
  }
}

class WidgetB extends StatelessWidget {
  static int count = 0;

  WidgetB({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<WidgetACubit, void>(
      builder: (context, state) {
        return Text("I've been rebuilt $count times");
      },
    );
  }
}

【问题讨论】:

    标签: flutter dart flutter-layout bloc flutter-bloc


    【解决方案1】:

    BlocBuilder 小部件通过订阅 Cubit 的状态流来工作。因此,您将无法使用 BlocBuilder 重建您的小部件,同时完全避免使用任何状态对象。你可以只使用一个没有任何方法和属性的虚拟状态类来表示你的 Cubit 的状态,并在你调用 cubit.doSomething 时发出一个新的实例。或者,您可以创建一个用于重建的自定义小部件,而不是 BlocBuilder。

    【讨论】:

    • 感谢您的明确回答,有没有办法在没有这种“hacky”解决方法的情况下做到这一点?
    • 我不太确定你为什么想做你想做的事,但有点“正确”的方式是不使用 bloc 。当您不想拥有任何状态时,您不需要状态管理解决方案。您可以创建一个自定义小部件来实现您想要的行为。
    【解决方案2】:

    它总是发出相同的实例(null),这就是它不会重建的原因。如果你坚持像这样重建它,你可以发出不同的值,比如

    class WidgetACubit extends Cubit<void> {
      WidgetACubit({initialState}) : super(initialState);
      int count = 0;
      void doSomething() => emit(count++);
    }
    

    顺便说一句,我不明白为什么你需要使用 void cubit 可以在 bloc 上举办活动。

    您可以查看flutter bloccore concepts 了解更多信息。

    【讨论】:

    • 谢谢回复,我之所以不用事件来存储状态,是因为这种情况下确实只有一个事件需要存储,就是按钮是否被按下。我愿意接受有关如何减少“hacky”的建议,但是如果不存储您提到的虚拟状态,我真的看不出如何做到这一点。
    【解决方案3】:

    我无法将代码添加为原始答案的注释,因为它太长了。

    class RebuildInvoker extends InheritedWidget {
      const RebuildInvoker({
        Key? key,
        required Widget child,
        required this.rebuild,
      }) : super(key: key, child: child);
    
      static RebuildInvoker of(BuildContext context) {
        final RebuildInvoker? result =
            context.dependOnInheritedWidgetOfExactType<RebuildInvoker>();
        assert(result != null, 'No RebuildChild found in context');
        return result!;
      }
    
      final void Function() rebuild;
    
      @override
      bool updateShouldNotify(RebuildInvoker oldWidget) {
        return oldWidget.rebuild != rebuild;
      }
    }
    
    class InjectRebuildInvoker extends StatefulWidget {
      const InjectRebuildInvoker({
        super.key,
        required this.child,
      });
    
      final Widget child;
    
      @override
      State<InjectRebuildInvoker> createState() => _InjectRebuildInvokerState();
    }
    
    class _InjectRebuildInvokerState extends State<InjectRebuildInvoker> {
      @override
      Widget build(BuildContext context) {
        return RebuildInvoker(
          child: widget.child,
          rebuild: () => setState(() {}),
        );
      }
    }
    

    您可以使用这样的自定义小部件来实现您想要的行为。用 InjectRebuildInvoker 包装一个小部件,当您想从其中一个子级中重建该小部件及其所有子级时,请调用 RebuildInvoker.of(context).rebuild()。不知道你为什么要这样做。顺便说一句,我没有测试代码。

    【讨论】:

      猜你喜欢
      • 2021-02-17
      • 2020-03-26
      • 2020-04-29
      • 2020-06-15
      • 2020-03-27
      • 2017-05-31
      • 2022-10-14
      • 1970-01-01
      • 2020-11-06
      相关资源
      最近更新 更多