How to make a bloc global accessible
Asked Answered
S

2

6

I am struggling to put the block pattern in my Flutter App. I am using this library to make it a little bit simpler for me: https://felangel.github.io/bloc/#/

I have one main Question. How can I make my Bloc globally accessible without passing it down again and again?

Here is my Code:

main.dart:

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

import 'db_bloc.dart';
import 'NotesPage.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  final DatabaseBloc _dbNoteBloc = DatabaseBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider<DatabaseBloc>(
        bloc: _dbNoteBloc,
        child: NotesPage(),
      ),
    );
  }

  @override
  void dispose() {
    _dbNoteBloc.dispose();
    super.dispose();
  }
}

NotesPage:

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

import 'db_bloc.dart';
import 'note_model.dart';

class NotesPage extends StatefulWidget {
  _NotesPageState createState() => _NotesPageState();
}

class _NotesPageState extends State<NotesPage> {
  @override
  Widget build(BuildContext context) {
    final DatabaseBloc _dbNoteBloc = BlocProvider.of<DatabaseBloc>(context);

    return BlocBuilder<NoteDbEvent, List<Note>>(
      bloc: _dbNoteBloc,
      builder: (BuildContext context, List<Note> state) {
        return Scaffold(
          appBar: AppBar(
            title: Text("bla"),
            actions: <Widget>[
              // action button
              IconButton(
                icon: Icon(Icons.refresh),
                onPressed: () => _dbNoteBloc
                    .dispatch(NoteDbEvent(type: NoteDbEventType.GetAll)),
              ), // action button
            ],
          ),
          body: ListView.builder(
            itemCount: state.length,
            itemBuilder: (BuildContext context, int index) {
              return Column(
                children: <Widget>[
                  ListTile(
                    title: Text('${state[index].title}'),
                    onLongPress: () => showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                              title: Text("Löschen"),
                              content: Text(
                                  "Möchtest du diese Notiz wirklich löschen?"),
                              actions: <Widget>[
                                FlatButton(
                                  child: Text("Close"),
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                ),
                                FlatButton(
                                  child: Text("Delete"),
                                  onPressed: () {
                                    _dbNoteBloc.dispatch(NoteDbEvent(
                                        value: state[index],
                                        type: NoteDbEventType.Delete));
                                    Navigator.of(context).pop();
                                  },
                                ),
                              ],
                            );
                          },
                        ),
                  ),
                  Divider(
                    height: 0,
                  ),
                ],
              );
            },
          ),
        );
      },
    );
  }
}

As you can see I also have the show Dialog Code inside of the widget code and I would love to source it out but until now the show Dialog Code was not able to access the _dbNoteBloc if it is not inside of the Bloc Builder.

Thank you for every help.

PS: If someone needs the Bloc Code here it is:

import 'package:bloc/bloc.dart';
import "note_model.dart";
import 'db.dart';

enum NoteDbEventType { Insert, Delete, Update, GetAll }

class NoteDbEvent {
  NoteDbEventType type;
  Note value;
  NoteDbEvent({this.type, this.value});
}

class DatabaseBloc extends Bloc<NoteDbEvent, List<Note>> {
  final db = DBProvider();

  @override
  List<Note> get initialState =>  [];

  @override
  Stream<List<Note>> mapEventToState(List<Note> currentState, NoteDbEvent event) async* {
    switch (event.type) {
      case NoteDbEventType.Delete:
        db.deleteNote(event.value.id);
        currentState.removeWhere((item) => item.id == event.value.id);
        yield List.from(currentState);
        break;
      case NoteDbEventType.Insert:
        int id = await db.newNote(event.value);
        event.value.id = id;
        currentState.add(event.value);
        yield List.from(currentState);
        break;
      case NoteDbEventType.Update:
        yield currentState;
        break;
      case NoteDbEventType.GetAll:
        var list = await db.getAllNotes();
        yield currentState = list;
        break;
    }
  }
}
Seafowl answered 4/2, 2019 at 17:30 Comment(1)
An advise if you are using BLoC pattern to manage the state of you whole app is a better choice use Redux pattern to do this instead. The BLoC pattern is better used to manage state of a single specific widget like a screen by example. Take a look at this article it will clear your mind.Converted
T
4

this is for version 8.0, now the page have an article of this topic: https://bloclibrary.dev/#/recipesflutterblocaccess?id=global-access

basically, you need to make the BlocProvider Parent of the material app, here what is show in the link (in case is dead now):

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 BlocProvider(
      create: (BuildContext context) => CounterBloc(),
      child: MaterialApp(
        title: 'Flutter Demo',
        home: CounterPage(),
      ),
    );
  }

and the key text in page is:

Wrapping the entire MaterialApp in a BlocProvider is the key to making our CounterBloc instance globally accessible. Now we can access our CounterBloc from anywhere in our application where we have a BuildContext using BlocProvider.of(context);

Tieck answered 27/7, 2022 at 18:58 Comment(0)
S
2

The BLoC pattern is better used to manage state of a single specific widget like a screen by example.

The BLoC pattern is not use by a single specific widget but use for each UI feature. It means that your widget is not hardly linked to your BLoC. You always have the choice to use it or not for each part of your UI. And it's obviously your work to split your BLoCs into multiple BLoCs.

For who don't know about it : if you want to make your life easier with BLoC pattern you can use the flutter_bloc package here that give you access to many helpers.

If you need help with the package you can also come to the gitter.

About displaying the Dialog you can maybe use the BlocListener that is quite new.

Sherfield answered 23/6, 2019 at 8:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.