I have a problem using Flutter Provider... My flow is like this: After login user id is passed to new widget -> from there it preforms save to db and then it redirects to new widget (Dashboard).
And this is a code of a widget after Login:
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: <Widget>[
Container(
margin: EdgeInsets.all(8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: InkWell(
onTap: () {
var user = Provider.of<UserRepository>(context);
user.savePreference(user.user.id, "Something");
user.navigateToNewPage(Dashboard(), context);
print(user.user.id);
},
This works:
user.savePreference(user.user.id, "Something");
But this is causing a problem:
user.navigateToNewPage(Dashboard(), context);
In Dashboard widget I am creating this:
Widget build(BuildContext context) {
var user = Provider.of<UserRepository>(context);
And in UserRepository I have this:
class UserRepository with ChangeNotifier {
User user;
Status _status = Status.Uninitialized;
Status get status => _status;
User get getUser => user;
UserRepository.instance();
Future<void> navigateToNewPage(Widget page, BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) => page));
}
I know this topic has already solved questions, but could not find anything suitable to my problem.
MaterialApp
> provider(Screen A)
> Screen B
If Provider
is instantiated in Screen A, it won't be accessible in Screen B after a Navigator.push
from A → B.
Because Provider
is an InheritedWidget
and Navigator
uses MaterialApp context
outside its Screen A context
scope. (See Details below.)
Moving Provider
up to a common-parent, MaterialApp context
, allows both Screen A and B to inherit its state/context.
provider(MaterialApp)
> Screen A
> Screen B
Example
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// wrap MaterialApp in Provider widget
return ChangeNotifierProvider(
create: (context) => ColorModel(), // ← create/init your state model
child: MaterialApp(
home: ScreenA()
),
);
}
}
Provider
is based on InheritedWidget
. Only child widgets can inherit parent widget's state.
Provider
needs to be the root widget for any widget tree that wants access to your "provided" state object.Navigator.push(context)
on Screen A doesn't use the context
from Screen A.
context
from MaterialApp
.Navigator.push(context)
is actually Navigator.of(context).push
Navigator.of(context)
means: search up this context hierarchy until you find a context that instantiated a Navigator
Navigator
is instantiated in MaterialApp
.Navigator
, you're using the default.Navigator
's context
is that of MaterialApp
.MaterialApp
), not the context of Screen A.
context
A.MaterialApp
context
, not of Screen A context
.Provider
context
scope, if defined in Screen A, doesn't cover Screen BScreen A → B
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))
is actually:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))
which is like:
Navigator.of(MaterialApp).push(
MaterialPageRoute(builder: (MaterialAppContext) => ScreenB())
)
So Screen B is under MaterialApp context
, not under Screen A context
and therefore has no access to Screen A Provider
and its context
.
See this answer for a code sample to a similar question about Provider
.