Bloc: BlocProvider.of<BlocA>(context) inside showModalBottomSheet

Created on 27 Oct 2019  ·  14Comments  ·  Source: felangel/bloc

Describe the bug
Error when use BlocProvider.of<BlocA>(context) inside on showModalBottomSheet

To Reproduce
Steps to reproduce the behavior:

I migrate flutter_bloc from 0.22.1 to 1.0.0 using BlocProvider.value and this worked correctly

BlocProvider.value(
  value: BlocProvider.of<BlocA>(context),
  child: ScreenA(),
);

but when migrate to 1.0.0 the problem appears.

I had to use a StatefulWidget widget and put the global provider and this worked

*Logs *
Run flutter analyze and attach any output of that command below.
If there are any analysis errors, try resolving them before filing this issue.

Paste the output of running flutter doctor -v here.
[✓] Flutter (Channel stable, v1.9.1+hotfix.5, on Mac OS X 10.15 19A602, locale en-PA)
• Flutter version 1.9.1+hotfix.5 at /Users/juliosena/flutter
• Framework revision 1aedbb1835 (10 days ago), 2019-10-17 08:37:27 -0700
• Engine revision b863200c37
• Dart version 2.5.0

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
• Android SDK at /Users/juliosena/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-28, build-tools 28.0.3
• ANDROID_HOME = /Users/juliosena/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.1, Build version 11A1027
• CocoaPods version 1.8.3

[✓] Android Studio (version 3.5)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 40.2.2
• Dart plugin version 191.8593
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] VS Code (version 1.39.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.5.1

[✓] Connected device (1 available)
• iPhone 8 • 69278E1C-E871-4F78-A235-313AD32257B6 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-1 (simulator)

• No issues found!

question

Most helpful comment

@b1acKr0se yup but if you just provide the bloc type and the state type the BlocBuilder will do the lookup for you and you don't have to worry about it 👍

All 14 comments

Hi @jcsena 👋
Thanks for opening an issue!

Are you able to provide a sample app which illustrates the issue? Thanks! 👍

A simple example with expected behaviour:

class Example extends StatelessWidget {
  const Example({Key key}) : super(key: key);


  Future<PlayerModel> _onShowSelectPlayer(BuildContext context){
        return showModalBottomSheet<PlayerModel>(){
          return BlocProvider.value(
            value: BlocProvider.of<MatchDetailBloc>(context),
            child:MatchHomeTeamLineUp(
                    match: widget._match,
                    onTap: (PlayerModel player) {
                    Navigator.of(context).pop(player);
                    },
                )
          );
      }
}

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: (){
        _onShowSelectPlayer(context);
      }
      child: Center(child:Text('Example')),
    );
  }
}

The MatchDetailBloc cannot be found in version 1.0.0 but in version 0.22.1 it work

Temporally solution for me (StatefulWidget)

class Example extends StatefulWidget {
  Example({Key key}) : super(key: key);

  @override
  _ExampleState createState() => _ExampleState();
}


class _ExampleState extends State<Example> {

  MatchDetailBloc _matchDetailBloc;

  @override
  void initState() { 
     _matchDetailBloc = BlocProvider.of<MatchDetailBloc>(context);
    super.initState();
  }

   Future<PlayerModel> _onShowSelectPlayer(BuildContext context){
        return showModalBottomSheet<PlayerModel>(){
          return BlocProvider.value(
            value: BlocProvider.of<MatchDetailBloc>(context),
            child:MatchHomeTeamLineUp(
                    match: widget._match,
                    onTap: (PlayerModel player) {
                    Navigator.of(context).pop(player);
                    },
                )
          );
      }
}

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: (){
        _onShowSelectPlayer(context);
      }
      child: Center(child:Text('Example')),
    );
  }

}

@jcsena can you provide a link to a complete sample app which I can run locally? It would make it much easier for me to debug the issue. Thanks! 🙏

@felangel Unfortunately, I cannot share the project but basically the problem originated when I migrated from version 0.21.1 to version 1.0.0 of flutter_bloc but this worked correctly.

@jcsena can you please create a new minimal sample app which reproduces the problem?

@felangel sure, I can, in a moment I upload the link

Thanks I’ll take a look shortly!

@jcsena I opened a pull request to fix the issue. The problem is you can't use the context of the bottom sheet's builder because its BuildContext is detached from the HomePage's context. All you need to do is use the parent BuildContext instead when doing the bloc lookup.

Hope that helps 👍

I have the same issue @felangel how to pass parent context into the modelbottomsheet to lookup bloc can you give one example?

@vishweshsoni in that case I would recommend performing the looking before showing the modal sheet and injecting the bloc directly via constructor.

//_vis is parent context which I am  passing into bottom sheet but bottom sheet does not update count variable in itself though it update in the main screen
showModalBottomSheet<FirstCounterBloc>(
                        context: _vis,
                        builder: (context) {
                          return Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: <Widget>[
                              Baseline(
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                                  children: <Widget>[
                                    Text(
                                      "Counter 1",
                                      style: TextStyle(color: Colors.pink,),
                                    ),
                                    SizedBox(width: 10.0,),
                                    Text(
                                      "${count}",
                                      style: TextStyle(color: Colors.black38),
                                    ),
                                    SizedBox(width: 10.0,),
                                    IconButton(icon: Icon(Icons.arrow_drop_up,color: Colors.pink,size:20.0), onPressed: (){
                                      BlocProvider.of<FirstCounterBloc>(_vis).add(eventType.first);
                                    }
                                    ),
                                    SizedBox(width: 10.0,),
                                    IconButton(icon: Icon(Icons.arrow_drop_down,color: Colors.pink,size: 20.0,), onPressed: (){
                                      setState(() {
                                        widget.one=widget.one+1;
                                      });
                                    }
                                    ),

                                  ],
                                ),
                                baseline: 0,
                                baselineType: TextBaseline.alphabetic,
                              ),

                              MaterialButton(
                                onPressed: () {
                                  Navigator.pop(context);
                                },
                                shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(19.0),
                                    side: BorderSide(color: Colors.pinkAccent)),
                                color: Colors.white,
                                child: Text(
                                  "Next",
                                  style: TextStyle(color: Colors.pinkAccent),
                                ),
                              )
                            ],
                          );
                        });

@felangel

@felangel We can use the correct context for BlocProvider.of but how about BlocBuilder? How to specify the correct context for it?

Edit: nevermind, BlocBuilder has a parameter named bloc so you can use the bloc you get from BlocProvider.of.

@b1acKr0se yup but if you just provide the bloc type and the state type the BlocBuilder will do the lookup for you and you don't have to worry about it 👍

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rsnider19 picture rsnider19  ·  3Comments

nerder picture nerder  ·  3Comments

wheel1992 picture wheel1992  ·  3Comments

krusek picture krusek  ·  3Comments

komapeb picture komapeb  ·  3Comments