จะส่งเหตุการณ์ Bloc ออกไปนอกวิดเจ็ตได้อย่างไร?

Aug 18 2020

ฉันเพิ่งเริ่มใช้สถาปัตยกรรม Bloc และฉันได้ดูบทแนะนำบางอย่างเมื่อเร็ว ๆ นี้ ฉันมีเพจที่เป็น StatelessWidget และข้างในฉันใช้ BlocProvider เพื่อเริ่มต้น Bloc ภายใน UI ของฉัน มันจะส่งคืนวิดเจ็ตที่แตกต่างกันตามการเปลี่ยนแปลงสถานะ

แต่แม้กระทั่งในบทช่วยสอนพวกเขาส่งเหตุการณ์จากวิดเจ็ตอื่น ๆ เท่านั้น (ตัวอย่างเช่นโดยการกดปุ่ม) แต่ในสถานการณ์ของฉันฉันต้องเรียกการเรียกใช้ init API นอก Widget ซึ่งอยู่ใน Bloc Event

ถ้าฉันอยู่ใน 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,
                        );
                      }
                    },
                  ),
                ],
              ),
            ],
          ),
        )));
  }
}

คำตอบ

1 Kherel Aug 18 2020 at 15:30

คุณต้องใช้วิธีอื่นในการรับกลุ่ม

BlocProvider.of(context)ใช้Providerใต้ฝากระโปรง ของผู้ให้บริการInheritedWidgetเป็นแพคเกจกระพือตัดที่ InheritedWidgetเป็นวิดเจ็ตที่กระพือปีกที่ส่งผ่านข้อมูลไปยังโครงสร้างวิดเจ็ตผ่านบริบท

ดังนั้นคุณต้องมีวิธีอื่น ตัวอย่างเช่นคุณสามารถใช้ไลบรารี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 และหลังจากนั้นคุณจะได้รับและนำไปใช้โดยไม่ต้องมีบริบท