how to access flutter bloc in the initState method?
Asked Answered
T

3

15

In the code shown below , the dispatch event is called from within the build method after getting the BuildContext object. What if I wish to do is to dispatch an event during processing at the start of the page within the initState method itself ?

If I use didChangeDependencies method , then I am getting this error : BlocProvider.of() called with a context that does not contain a Bloc of type FileManagerBloc. how to fix this?

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=>FileManagerBloc(),
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

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

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    final FileManagerBloc bloc = BlocProvider.of<FileManagerBloc>(context) ;
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        bloc.dispatch(SetCurrentWorkingDir(path)) ;
        bloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }
Tremolo answered 7/9, 2019 at 15:6 Comment(0)
M
10

The problem is that you are initializing the instance of FileManagerBloc inside the BlocProvider which is, of course inaccessible to the parent widget. I know that helps with automatic cleanup of the Bloc but if you want to access it inside initState or didChangeDependencies then you have to initialize it at the parent level like so,

FileManagerBloc _fileManagerBloc;

@override
void initState() {
  super.initState();
  _fileManagerBloc= FileManagerBloc();
  _fileManagerBloc.dispatch(LoadEducation());
}

@override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=> _fileManagerBloc,
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

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

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        _fileManagerBloc.dispatch(SetCurrentWorkingDir(path)) ;
        _fileManagerBloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }

alternatively, if FileManagerBloc was provided/initialized at a grandparent Widget then it could easily be accessible at this level through BlocProvider.of<CounterBloc>(context);

Mediate answered 12/9, 2019 at 4:53 Comment(0)
A
2

you can use it in didChangeDependencies method rather than initState.

Example

 @override
  void didChangeDependencies() {
    final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
    //do whatever you want with the bloc here.
    super.didChangeDependencies();
  }
Annunciata answered 7/9, 2019 at 16:12 Comment(3)
BlocProvider.of<CounterBloc>(context is raising an error , I have updated my question , please suggest a fixTremolo
Not sure why this is downvoted. It's a legit way of accessing bloc. I am using it in didChangeDependencies. In parent widget I have BlocProvider so I have access to the bloc in child widgets. I am using it to fire event using counterBloc.add(...) every time I navigate to specific view.Waterer
to fire bloc events in didChangeDependencies is very bad practice - check how many times this can fire in complex widgets especially. It is safe to use context here, but not consistent.Bostow
S
1

Solution: Step 1: need apply singleton pattern on Bloc class

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  static AuthBloc? _instance;
  static AuthBloc get instance {
    if (_instance == null) _instance = AuthBloc();
    return _instance!;
  }
  ....
  ....

Step 2: use AuthBloc.instance on main.dart for Provider

void main() async {
  runApp(MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => AuthBloc.instance,
      ),
      ...
      ...
    ],
    child: App(),
  ));
}

Now you can use Bloc without context

  1. you can get state by AuthBloc.instance.state from initState or anywhere
  2. you can add event from anywhere by AuthBloc.instance.add(..)
  3. you also call BlocA from another BlocB very simple
Sworn answered 19/4, 2022 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.