Describe the bug
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: BlocProvider.of() called with a context that does not contain a Bloc of type ProfileBlocs.
E/flutter ( 7314): No ancestor could be found starting from the context that was passed to BlocProvider.of<ProfileBlocs>().
E/flutter ( 7314):
I checked same issues faced by others. but i'm not able to fix it.
I'm not sure whether i'm missing something. Please help me out
Here is code
class ProfileScreen extends StatefulWidget {
ProfileScreen({Key key}) : super(key: key);
@override
_ProfileScreenState createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
final TextEditingController _firstNameTEC = TextEditingController();
final TextEditingController _lastNameTEC = TextEditingController();
final TextEditingController _emailTEC = TextEditingController();
final _formKey = GlobalKey<FormState>();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ProfileBlocs(),
child: Scaffold(
appBar: customAppBar("Basic Details"),
body: _bodyWidget(),
floatingActionButton: FloatingActionButton(
onPressed: () => prefs.clear(),
child: Icon(Icons.navigate_next),
),
));
}
Widget _bodyWidget() {
return SingleChildScrollView(
child: Form(
key: _formKey,
child: BlocBuilder<ProfileBlocs, ApiResponse>(builder: (_, state) {
return Column(
children: <Widget>[
customTextFormField("First Name", controller: _firstNameTEC),
customTextFormField("Last Name", controller: _lastNameTEC),
customTextFormField("Email", controller: _emailTEC),
RaisedButton(
child: Text("Submit"),
onPressed:
state.status == ApiStatus.LOADING ? null : _submitData,
)
],
);
})),
);
}
void _submitData() async {
if (_formKey.currentState.validate()) {
final customer = Customer.basic(
firstName: _firstNameTEC.trimText(),
lastName: _lastNameTEC.trimText(),
email: _emailTEC.trimText());
BlocProvider.of<ProfileBlocs>(context)
.add(SaveUserDetailsEvent(customer));
}
}
}
Hi, that is because you are using the same context for the BlocProvider
and the BlocBuilder
. By definition how lookup works that is not a valid way how to do it. You cannot access a bloc from the same context in which it was provided.
But if you don't want to make a new widget, you can use the Builder
widget to fix this issue.
Builder(
builder: (context) {
BlocProvider.of<MyBloc>(context);
}
)
// Duplicate of https://github.com/felangel/bloc/issues/763
Thanks for the response @tenhobi
It's working now.
My concern is that can't I use directly.
Because i have different screens independent of other. Now for that screens I don't want to always create another state class or builder to use different context
Or this is the the way it works?
The thing is that you are using the same context, and therefore if you look up, nothing is above.
You need to create separate widgets or use Builder
, which will provide a different context. As I already mentioned.
You can watch https://bloclibrary.dev/#/recipesflutterblocaccess this tutorial to see how to make Bloc assessable.
@felangel do you think it would be good to put this feature on flutter_bloc?
The child of BlocProvider could be wrapped in a Builder by default. Are there any side effects of doing that?
@rahuldange09 what you're suggesting will not help because the you would still be using your context instead of the Builder
context since the Builder
will be internal to BlocProvider
.
The only way to expose it would be to change the BlocProvider
API to have a builder
instead of child
@override
Widget build(BuildContext contextA) {
BlocProvider(
create: (contextB) => BlocA(),
builder: (contextC) {
// BlocProvider.of<BlocA>(contextA) -> FAIL
// BlocProvider.of<BlocA>(contextB) -> SUCCESS
// BlocProvider.of<BlocA>(contextC) -> SUCCESS
}
);
}
Let me know if that helps.
Closing for now but feel free to comment with additional feedback and I'm happy to continue the conversation.
You probably forgot to wrap your main app to BlocProvider? Which it would give you the Bloc for all your children widget, just like inherited widget
Most helpful comment
Hi, that is because you are using the same context for the
BlocProvider
and theBlocBuilder
. By definition how lookup works that is not a valid way how to do it. You cannot access a bloc from the same context in which it was provided.But if you don't want to make a new widget, you can use the
Builder
widget to fix this issue.// Duplicate of https://github.com/felangel/bloc/issues/763