【问题标题】:How to dispatch Bloc events outside of Widget?如何在 Widget 之外调度 Bloc 事件?
【发布时间】:2020-12-07 09:10:15
【问题描述】:

我是 Bloc 架构的新手,最近看了一些教程。我有一个 StatelessWidget 页面,在里面我使用 BlocProvider 在我的 UI 中初始化 Bloc。它将根据状态变化返回不同的小部件。

但即使在教程中,它们也仅从其他小部件(例如通过按下按钮)分派事件。但在我的情况下,我需要在 Bloc Event 中的 Widget 之外调用 init API。

如果我在其他 Widget 中,我可以调用 BlocProvider.of<FirstTabBloc>(context).dispatch(GetUserProfile());,但我不能在 main() 中调用它,因为上下文不是来自 Widget。

代码:

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: firstTabElement(context),
      ),
      appBar: EmptyAppBar(mainAppColor),
    );
  }

  BlocProvider<FirstTabBloc> firstTabElement(BuildContext context) {
    return BlocProvider(
        builder: (_) => sl<FirstTabBloc>(),
        child: Expanded(
            child: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: <Widget>[
              Stack(
                children: [
                  //Main Background
                  Column(children: <Widget>[
                    //Top part
                    Container(
                      constraints: BoxConstraints(
                        minHeight: 120,
                      ),
                      width: MediaQuery.of(context).size.width,
                      height: 300,
                      decoration: new BoxDecoration(
                        gradient: LinearGradient(
                          begin: Alignment.topCenter,
                          end: Alignment.bottomCenter,
                          colors: ticketGradient,
                        ),
                      ),
                    ),
                    // Bottom part - white
                    Container(
                      color: basicWhite,
                    ),
                  ]),
                  //content above background
                  BlocBuilder<FirstTabBloc, FirstTabState>(
                    builder: (context, state) {
                      if (state is Uninitialized) {
                        return WalletWidget(
                          credit: formatPrice(0),
                          currency: '€',
                        );
                      } else if (state is Loading) {
                        return LoadingWidget();
                      } else if (state is Loaded) {
                        Wallet currWallet = state.profile.getWalletByClient(clientId);
                        return WalletWidget(
                          credit: formatPrice(currWallet.value),
                          currency: formatCurrency(currWallet.currency),
                        );
                      } else if (state is Error) {
                        return MessageDisplay(
                          message: state.message,
                        );
                      }
                    },
                  ),
                ],
              ),
            ],
          ),
        )));
  }
}

【问题讨论】:

  • 为什么在 main 中需要它?
  • 我想在启动时调用 API,结果会改变状态/在屏幕上绘制不同的小部件。
  • 在 main 中这样做可能不是一个好主意。您应该使用某种闪屏或用户交互的东西。不建议在 main 中进行繁重的工作。

标签: flutter flutter-bloc


【解决方案1】:

你需要用另一种方式来获得集团。

BlocProvider.of(context) 在后台使用ProviderProvider 是一个颤振包,它包裹了 InheritedWidgetInheritedWidget 是 Fl​​utter 小部件,它通过上下文将数据向下传递到小部件树。

所以你需要另一种方式。例如,您可以使用 get_it 库。这是Service Locator 的飞镖实现。

小部件外部块的简单示例

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

final bloc = CounterBloc();

void main() {
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);

  runApp(
    MyApp(),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => bloc,
      child: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: BlocBuilder<CounterBloc, int>(
        builder: (_, count) {
          return Center(
            child: Text('$count', style: Theme.of(context).textTheme.headline1),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: const Icon(Icons.add),
              onPressed: () =>
                  context.bloc<CounterBloc>().add(CounterEvent.increment),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: const Icon(Icons.remove),
              onPressed: () =>
                  context.bloc<CounterBloc>().add(CounterEvent.decrement),
            ),
          ),
        ],
      ),
    );
  }
}

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield state - 1;
        break;
      case CounterEvent.increment:
        yield state + 1;
        break;
      default:
        addError(Exception('unsupported event'));
    }
  }
}

在 get_it 中注册您的集团。之后,您可以在没有上下文的情况下获取并使用它。

【讨论】:

  • 我正在使用它'sl()'。 sl 是 GetIt 实例。这意味着我可以在 main 中调用它,例如 'sl().dispatch(GetUserProfile());' ?
  • 好。我已经添加了示例。您可以以相同的方式执行此操作,但不是在全局上下文中而是使用 get_it 创建所需的块。
  • 这是你要找的还是你需要更好的例子?
【解决方案2】:

我想你需要知道 dispatch renamed to add

> There were core api changes introduced into 1.0.0:
bloc.state.listen -> bloc.listen
bloc.currentState -> bloc.state
bloc.dispatch -> bloc.add
bloc.dispose -> bloc.close

查看https://link.medium.com/qnfMcEcW00 了解更多详情。 希望对你有帮助?

【讨论】:

    猜你喜欢
    • 2020-03-23
    • 2020-12-06
    • 2019-12-06
    • 2020-02-18
    • 2021-08-28
    • 2021-04-23
    • 2019-06-12
    • 2018-11-20
    • 2020-12-19
    相关资源
    最近更新 更多