Could not find the correct Provider<X> above this Y Widget In Flutter with navigational flows
Solution 1
When performing navigation using Navigator.of(context)
the route you push becomes part of the widget tree of your MaterialApp
via its internal default Navigator
. However, that route does not become a child of ChangeNotifierProvider
but of the MaterialApp
.
You should make the provider an ancestor of your MaterialApp
.
Solution 2
Move ChangeNotifier
above MyApp
:
void main() {
runApp(ChangeNotifierProvider(
builder: (context) => ContentDS(),
child: MyApp()));
}

Debanjan Chakraborty
Updated on December 14, 2022Comments
-
Debanjan Chakraborty 14 minutes
I am not unerstanding why the Provider is not being accepted here.
My main.dart looks like this.
class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, ), home: ChangeNotifierProvider<ContentDS>( builder: (_) => ContentDS(), child: Content(), ) ); } }
Provider works perfectly in Content Class. Now I move from Content to Content Details using this code
Navigator.of(ctx).push(MaterialPageRoute( builder: (context) => ContentDetails(viewedList: listElement), ))
In Content Details, I am just trying to access the Provider again
final ds = Provider.of<ContentDS>(context);
But this gives me the following error
Error: Could not find the correct Provider above this ContentDetails Widget
To fix, please:
- Ensure the Provider is an ancestor to this
ContentDetails Widget * Provide types to Provider *
Provide types to Consumer * Provide types to
Provider.of() * Always use package imports. Ex:
import 'package:my_app/my_code.dart'; * Ensure the correct
context` is being used.
Content-Details code
class ContentDetails extends StatefulWidget { ToDoList viewedList; ContentDetails({this.viewedList}); @override _ContentDetailsState createState() => _ContentDetailsState(); } class _ContentDetailsState extends State<ContentDetails> with SingleTickerProviderStateMixin{ bool isOpened = false; AnimationController _animationController; Animation<Color> _buttonColor; Animation<double> _animateIcon; Animation<double> _translateButton; Curve _curve = Curves.easeOut; double _fabHeight = 56.0; initState() { _animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 500)) ..addListener(() { setState(() {}); }); _animateIcon = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController); _buttonColor = ColorTween( begin: Colors.blue, end: Colors.red, ).animate(CurvedAnimation( parent: _animationController, curve: Interval( 0.00, 1.00, curve: Curves.linear, ), )); _translateButton = Tween<double>( begin: _fabHeight, end: -14.0, ).animate(CurvedAnimation( parent: _animationController, curve: Interval( 0.0, 0.75, curve: _curve, ), )); super.initState(); } @override dispose() { _animationController.dispose(); super.dispose(); } animate() { if (!isOpened) { _animationController.forward(); } else { _animationController.reverse(); } isOpened = !isOpened; } @override Widget build(BuildContext context) { final ds = Provider.of<ContentDS>(context); print(" ds.count ---> " + ds.count.toString()); if (widget.viewedList != null){ debugPrint(" widget.viewedList.primaryID ---> " + widget.viewedList.primaryID); }else{ debugPrint(" It is null"); } return Hero( tag: (widget.viewedList != null) ? widget.viewedList.primaryID : 'Hero', child: Scaffold( appBar: new AppBar( backgroundColor: ListStatusHelper.getBgGenericColor(widget.viewedList?.status ?? ListStatus.NONE), title: Text('${getListTitle()}'), elevation: 0.0, ), floatingActionButton: Wrap( direction: Axis.vertical, children: <Widget>[ transformWorks(edit(), 3), transformWorks(save(), 2), transformWorks(inbox(),1), toggleButton() ], ), body: Container( color: ListStatusHelper.getBgGenericColor(widget.viewedList?.status ?? ListStatus.NONE), child: const Text("Once Provider is available, need to work on this section"); ), ), ); } Widget transformWorks(Widget btn, int pos){ return Transform( transform: Matrix4.translationValues( 0.0, _translateButton.value * pos, 0.0, ), child: btn, ); } Widget inbox() { return Container( child: FloatingActionButton( heroTag: null, onPressed: null, tooltip: 'Inbox', elevation: 0.0, child: Icon(Icons.inbox), ), ); } Widget edit() { return Container( child: FloatingActionButton( heroTag: null, onPressed: null, tooltip: 'Edit', elevation: 0.0, child: Icon(Icons.edit), ), ); } Widget save() { return Container( child: FloatingActionButton( heroTag: null, onPressed: null, tooltip: 'Save', elevation: 0.0, child: Icon(Icons.save), ), ); } Widget toggleButton(){ return FloatingActionButton( heroTag: null, backgroundColor: _buttonColor.value, onPressed: animate, tooltip: 'Toggle', child: AnimatedIcon( icon: AnimatedIcons.menu_close, progress: _animateIcon, ), ); } String getListTitle() { if (widget.viewedList != null) { return widget.viewedList.listTitle; } else { return 'New List'; } } }
I am an iOS developer who is trying to learn flutter, and I thought that Provider should be available to all classes that belong within a navigational flow, without utilising any DI.
Help me realise what am I missing. How should Provider be used in case of navigational flows such as aforementioned cases.
Thanks in advance
-
Andrey Gordeev about 3 yearsPlease add code of
ContentDetails
widget -
Debanjan Chakraborty about 3 yearsAdded the Content Details
-
rstrelba about 3 yearsWhy not move up provider class with MaterialApp as child of provider?
-
Debanjan Chakraborty about 3 yearsSo, you mean that the child for ChangeNotifierProvider<ContentDS> will be the material app? How does that solve the problem?
- Ensure the Provider is an ancestor to this
ContentDetails Widget * Provide types to Provider *
Provide types to Consumer * Provide types to
Provider.of() * Always use package imports. Ex: